当前位置: 首页 > news >正文

Qt Windows和Android使用MuPDF预览PDF文件

文章目录

  • 1. Windows MuPDF编译
  • 2. Android MuPDF编译
  • 3. 引用 MuPDF 库
  • 4. 解析本地PDF文件


1. Windows MuPDF编译

使用如下命令将MuPDF的源码克隆到本地

git clone --recursive git://git.ghostscript.com/mupdf.git

直接用VS,打开 mupdf/platform/win32/mupdf.sln 工程文件,然后编译即可,我这边用的是VS2019 编译的x64的版本,编译中并没有报错。 编译完成后会生成 libmupdf.lib 库文件。


2. Android MuPDF编译

使用如下命令将MuPDF的源码克隆到本地

git clone --recursive git://git.ghostscript.com/mupdf-android-viewer.git

(1) 修改 mupdf-android-viewer/jni/libmupdf/platform/java 路径下的 Android.mk 文件,添加
LOCAL_SHORT_COMMANDS := true

...
LOCAL_LDFLAGS := -Wl,--gc-sections
LOCAL_LDFLAGS += $(MUPDF_EXTRA_LDFLAGS)LOCAL_SHORT_COMMANDS := true
include $(BUILD_SHARED_LIBRARY)

(2) 修改 mupdf-android-viewer/jni/libmupdf/platform/java 路径下的 Application.mk 文件,添加
APP_SHORT_COMMANDS := true

APP_SHORT_COMMANDS := trueifdef USE_TESSERACT
APP_STL := c++_static
endif

然后打开 AndroidStudio 直接构建即可,最后会生成 libmupdf_java.so 文件,如果找不到可以用everything找一下,我的生成目录是在 mupdf-android-viewer/app/build/intermediates/merged_native_libs/debug/out/lib 下


3. 引用 MuPDF 库

Qt的.pro文件中增加如下配置,分别添加Windows和Android库的头文件和库文件目录

win32 {# PDFINCLUDEPATH += $$PWD/../thirdLibs/MuPDF/win/includeCONFIG(debug, debug|release) {LIBS += -L$$PWD/../thirdLibs/MuPDF/win/libs/Debug -llibmupdf}CONFIG(release, debug|release) {LIBS += -L$$PWD/../thirdLibs/MuPDF/win/libs/Release -llibmupdf}
}android {INCLUDEPATH += $$PWD/../thirdLibs/MuPDF/android/includeLIBS += -L$$PWD/../thirdLibs/MuPDF/android/libs -lmupdf_java
}

4. 解析本地PDF文件

头文件

#ifndef MUPDFWRAPERCORE_H
#define MUPDFWRAPERCORE_H#include <QObject>
#include <QImage>struct fz_context;
struct fz_document;
struct fz_pixmap;class UTILS_EXPORT MuPDFWraperCore : public QObject
{Q_OBJECTpublic:MuPDFWraperCore(QObject* parent = nullptr);~MuPDFWraperCore();// 初始化上下文void initContext(void);// 加载PDF文件bool loadPdfFile(const QString& pdfPath);// 读取PDF某一页QImage loadPdfPage(int nPage, qreal zoom = 100, qreal rotate = 0);// 获取总页数int getTotalPage(void);private:int m_nTotalPage = 0;fz_context *m_pCtx = nullptr;fz_document *m_pDoc = nullptr;fz_pixmap *m_pPix = nullptr;
};#endif

cpp文件

#include "MuPDFWraperCore.h"
#include "mupdf/fitz.h"
#include <QDebug>MuPDFWraperCore::MuPDFWraperCore(QObject* parent):QObject(parent)
{}MuPDFWraperCore::~MuPDFWraperCore()
{if (m_pPix)fz_drop_pixmap(m_pCtx, m_pPix);if (m_pDoc)fz_drop_document(m_pCtx, m_pDoc);if (m_pCtx)fz_drop_context(m_pCtx);m_pPix = nullptr;m_pDoc = nullptr;m_pCtx = nullptr;
}// 初始化上下文
void MuPDFWraperCore::initContext(void)
{if (m_pCtx == nullptr)m_pCtx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);if (!m_pCtx) {qInfo() << "Create PDF Context Error!";return;}/* Register the default file types to handle. */fz_try(m_pCtx)fz_register_document_handlers(m_pCtx);fz_catch(m_pCtx){
//        fz_report_error(m_pCtx);qInfo() << "cannot register document handlers";fz_drop_context(m_pCtx);m_pCtx = nullptr;return;}
}// 加载PDF文件
bool MuPDFWraperCore::loadPdfFile(const QString& pdfPath)
{if (m_pCtx == nullptr) {initContext();}if (m_pCtx == nullptr)return false;/* Open the document. */fz_try(m_pCtx)m_pDoc = fz_open_document(m_pCtx, pdfPath.toStdString().c_str());fz_catch(m_pCtx){
//        fz_report_error(m_pCtx);qInfo() << "cannot open document";fz_drop_context(m_pCtx);m_pCtx = nullptr;return false;}/* Count the number of pages. */fz_try(m_pCtx)m_nTotalPage = fz_count_pages(m_pCtx, m_pDoc);fz_catch(m_pCtx){
//        fz_report_error(m_pCtx);qInfo() << "cannot count number of pages";fz_drop_document(m_pCtx, m_pDoc);fz_drop_context(m_pCtx);m_pCtx = nullptr;m_pDoc = nullptr;return false;}return true;
}// 读取PDF某一页
QImage MuPDFWraperCore::loadPdfPage(int nPage, qreal zoom, qreal rotate)
{if (m_pCtx == nullptr || m_pDoc == nullptr)return QImage();if (nPage >= m_nTotalPage) {qInfo() << "Page Over Page Total Count";return QImage();}/* Compute a transformation matrix for the zoom and rotation desired. *//* The default resolution without scaling is 72 dpi. */fz_matrix ctm = fz_scale(zoom / 100, zoom / 100);ctm = fz_pre_rotate(ctm, rotate);/* Render page to an RGB pixmap. */if (m_pPix) {fz_drop_pixmap(m_pCtx, m_pPix);}fz_try(m_pCtx)m_pPix = fz_new_pixmap_from_page_number(m_pCtx, m_pDoc, nPage, ctm, fz_device_rgb(m_pCtx), 0);fz_catch(m_pCtx){
//        fz_report_error(m_pCtx);qInfo() << "cannot render page";fz_drop_document(m_pCtx, m_pDoc);fz_drop_context(m_pCtx);return QImage();}QImage image(m_pPix->w, m_pPix->h, QImage::Format_RGB888);for (int y = 0; y < m_pPix->h; ++y){unsigned char* p = &m_pPix->samples[y * m_pPix->stride];for (int x = 0; x < m_pPix->w; ++x){image.setPixel(x, y, qRgb(p[0], p[1], p[2]));p += m_pPix->n;}}return image/*QImage(m_pPix->samples, m_pPix->w, m_pPix->h, QImage::Format_RGB888)*/;
}// 获取总页数
int MuPDFWraperCore::getTotalPage(void)
{return m_nTotalPage;
}

上面的代码比较简单,基本操作API如下:

  • fz_new_context: 创建PDF上下文
  • fz_register_document_handlers: 注册要处理的默认文件类型
  • fz_open_document: 打开PDF文件
  • fz_count_pages: 获取PDF的总页数
  • fz_scale:获取缩放矩阵
  • fz_pre_rotate: 获取旋转矩阵
  • fz_new_pixmap_from_page_number:读取文档某一页并转化为图像

使用如下代码可将 fz_pixmap 转化为 QImage

QImage image(m_pPix->w, m_pPix->h, QImage::Format_RGB888);
for (int y = 0; y < m_pPix->h; ++y)
{unsigned char* p = &m_pPix->samples[y * m_pPix->stride];for (int x = 0; x < m_pPix->w; ++x){image.setPixel(x, y, qRgb(p[0], p[1], p[2]));p += m_pPix->n;}
}

最后直接渲染这个QImage就完成了PDF的预览 ^v^


效果截图:
Windows-PDF预览:
Windows-PD预览
Android-PDF预览:
Android-PDF预览

相关文章:

  • mac电脑flutter环境配置,解决疑难问题
  • 力扣:47. 全排列 II
  • Oracle12c之Sqlplus命令行窗口基本使用
  • LLaMA 模型中的Transformer架构变化
  • LabVIEW电能质量监测系统
  • 详述FlinkSql Join操作
  • c++设计模式之装饰器模式
  • 为电子表格嵌入数据库,Excel/WPS一键升级为管理系统
  • 零基础学Python之网络编程
  • 【Linux】缓冲区与缓冲区的刷新策略
  • 微信自动预约小程序开发指南:从小白到专家
  • 中兴R5300G4服务器查看服务器、主板序列号及硬盘RAID信息
  • 小白都能看懂的力扣算法详解——链表(一)
  • Linux文件和目录管理
  • 上海亚商投顾:成交量突破万亿 沪指重回2800
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【Amaple教程】5. 插件
  • CAP理论的例子讲解
  • Centos6.8 使用rpm安装mysql5.7
  • HTTP中GET与POST的区别 99%的错误认识
  • JavaScript中的对象个人分享
  • java中具有继承关系的类及其对象初始化顺序
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • Linux快速复制或删除大量小文件
  • Python十分钟制作属于你自己的个性logo
  • Transformer-XL: Unleashing the Potential of Attention Models
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • Vultr 教程目录
  • 分享一份非常强势的Android面试题
  • 使用SAX解析XML
  • !!Dom4j 学习笔记
  • #100天计划# 2013年9月29日
  • #pragam once 和 #ifndef 预编译头
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (ibm)Java 语言的 XPath API
  • (TOJ2804)Even? Odd?
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (七)c52学习之旅-中断
  • (四)库存超卖案例实战——优化redis分布式锁
  • (转载)Linux网络编程入门
  • .FileZilla的使用和主动模式被动模式介绍
  • .Net CF下精确的计时器
  • .net core 连接数据库,通过数据库生成Modell
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .NET Standard 的管理策略
  • .net 获取url的方法
  • .NET 设计一套高性能的弱事件机制
  • .vue文件怎么使用_我在项目中是这样配置Vue的
  • @Repository 注解
  • @RequestBody与@ModelAttribute
  • [20180312]进程管理其中的SQL Server进程占用内存远远大于SQL server内部统计出来的内存...
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • [BT]BUUCTF刷题第9天(3.27)
  • [bzoj1324]Exca王者之剑_最小割
  • [C#C++]类CLASS