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预览:
Android-PDF预览:
相关文章:
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 …...
MongoDB聚合:$replaceWith
r e p l a c e W i t h ‘ 可以将输入文档替换为指定的文档。该操作可以替换输入文档的所有字段,包括 ‘ i d ‘ 字段。使用 ‘ replaceWith可以将输入文档替换为指定的文档。该操作可以替换输入文档的所有字段,包括_id字段。使用 replaceWith‘可以将输…...
Vue 进阶系列丨实现简易VueRouter
Vue 进阶系列教程将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧! 2013年7月28日,尤雨溪第一次在 G…...
unity editor 编辑器 GUID localID LocalFileId 查找问题
//传入对象实例化ID 可以获取到 guid localid guid预设的ID localid 预设内的ID //这个方法有个问题如果在预设编辑器状态下 可能出现查不到 guid localid 原因可能 传入对象是是编辑状态下instanceid 并不是保存状态下的 UnityEditor.AssetDatabase.TryGetGUIDAndLocalF…...
【Mybatis】从0学习Mybatis(2)
前言 本篇文章是从0学习Mybatis的第一篇文章,由于篇幅太长CSDN会限流,因此我打算分开两期来写,这是第二期!第一期在这儿:【Mybatis】从0学习Mybatis(1)-CSDN博客 1.什么是ResultMap结果映射&am…...
ChatGPT高效提问—prompt常见用法(续篇九)
ChatGPT高效提问—prompt常见用法(续篇九) 如何准确地向大型语言模型提出问题,使其更好地理解我们的意图,从而得到期望的答案呢?编写有效的prompt的技巧,精心设计的prompt,获得期望的的答案。 1.1 增加条件 在各种prompt技巧中,增加条件是最常用的。在prompt中…...
echarts的title标题属性
echarts的title标题属性 title 标题组件,包含主标题和副标题。 位于 option对象第一层. title.text 设置主标题内容title.subtext 设置副标题内容 在 ECharts 2.x 中单个 ECharts 实例最多只能拥有一个标题组件。但是在 ECharts 3 中可以存在任意多个标题组件&am…...
【HTML+CSS】使用CSS中的Position与z-index轻松实现一个简单的自定义标题栏效果
🚀 个人主页 极客小俊 ✍🏻 作者简介:web开发者、设计师、技术分享博主 🐋 希望大家多多支持一下, 我们一起学习和进步!😄 🏅 如果文章对你有帮助的话,欢迎评论 💬点赞&a…...
从零开始:用 Rust 编写你的第一个 Web 服务
Rust 是一种现代、高性能的编程语言,近年来在 Web 开发领域也有了一席之地。本文将介绍如何使用 Rust 编写一个简单的 Web 程序,从搭建开发环境到创建第一个 Web 页面。 1. 开发环境搭建 首先,确保你已经安装了 Rust 工具链。你可以通过在终…...
机器学习复习(8)——逻辑回归
目录 逻辑函数(Logistic Function) 逻辑回归模型的假设函数 从逻辑回归模型转换到最大似然函数过程 最大似然函数方法 梯度下降 逻辑函数(Logistic Function) 首先,逻辑函数,也称为Sigmoid函数&#…...
深入解析MySQL 8:事务数据字典的变革
随着数据库技术的不断发展和完善,元数据的管理成为了一个日益重要的议题。在MySQL 8中,一项引人注目的新特性是引入了事务数据字典(Transaction Data Dictionary,简称TDD),它改变了元数据的管理方式&#x…...
jquery写表格,通过后端传值,并合并单元格
<!DOCTYPE html> <html> <head><title>Table Using jQuery</title><style>#tableWrapper {width: 100%;height: 200px; /* 设置表格容器的高度 */overflow: auto; /* 添加滚动条 */margin-top: -10px; /* 负的外边距值,根据实际…...
百家cms代审
参考博客: PHP代码审计之旅之百家CMS-腾讯云开发者社区-腾讯云 环境搭建 源码链接如下所示 https://gitee.com/openbaijia/baijiacms 安装至本地后 直接解压到phpstudy的www目录下即可 接下来去创建一个数据库用于存储CMS信息。(在Mysql命令行中执行…...
算法学习——LeetCode力扣二叉树篇3
算法学习——LeetCode力扣二叉树篇3 116. 填充每个节点的下一个右侧节点指针 116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode) 描述 给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树…...
强制卸载挂载目录
当遇到磁盘卸载失败提示 device is busy fuser -a 显示所有命令行中指定的文件,默认情况下被访问的文件才会被显示。 -c 和-m一样,用于POSIX兼容。 -k 杀掉访问文件的进程。如果没有指定-signal就会发送SIGKILL信号。结合 –signal -signal 使用指定的信…...
HiveSQL——sum(if()) 条件累加
注:参考文章: HiveSql面试题10--sum(if)统计问题_hive sum if-CSDN博客文章浏览阅读5.8k次,点赞6次,收藏19次。0 需求分析t_order表结构字段名含义oid订单编号uid用户idotime订单时间(yyyy-MM-dd)oamount订…...
Linux命令行工具使用HTTP代理的方法详解
亲爱的Linux用户们,有没有想过在命令行世界里,你的每一个指令都能悄无声息地穿越千山万水,而不被外界窥探?哈哈,没错,就是通过HTTP代理!今天,我们就来一起探索如何在Linux命令行工具…...
idea mavn 中途新建gitignore文件如何生效
两种情况下项目代码中新建gitignore文件如何生效。 第一种情况项目代码下没有模块的情况 直接在该项目代码的根目录下进入git命令行执行: git rm -r --cached . git add . 注意上面两个命令后面都有一个点 第二种情况是有模块的情况 需要进入模块目录执行上…...
Hadoop:认识MapReduce
MapReduce是一个用于处理大数据集的编程模型和算法框架。其优势在于能够处理大量的数据,通过并行化来加速计算过程。它适用于那些可以分解为多个独立子任务的计算密集型作业,如文本处理、数据分析和大规模数据集的聚合等。然而,MapReduce也有…...
9.4 OpenGL帧缓冲:纹理和帧缓冲之间的反馈循环
纹理和帧缓冲之间的反馈循环 Feedback Loops Between Textures and the Framebuffer 当在图形编程中,特别是OpenGL这样的图形API中处理纹理(Texture)和帧缓冲区(Framebuffer)时,可能会出现一种称为“反馈循…...
相机图像质量研究(6)常见问题总结:光学结构对成像的影响--对焦距离
系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结:光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结:光学结构对成…...
fast.ai 机器学习笔记(二)
机器学习 1:第 5 课 原文:medium.com/hiromi_suenaga/machine-learning-1-lesson-5-df45f0c99618 译者:飞龙 协议:CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它,这些笔记将继续更…...
vue3 elementplus DateTimePicker 日期时间设置默认时间为当天
DateTimePicker里面有个自带属性 可以实现这个需求,如图: // 设置当前当天时间范围 00: 00: 00 - 23:59:59 const currentDate [setDefaultDate(0), setDefaultDate(1)]const setDefaultDate (type:number ): string > {let t ;let date new Da…...
2024年笔记--centos docker离线安装启动失败
Failed to start Docker Application Container Engine 错误如下: [rootel70 docker]# systemctl start docker.service Job for docker.service failed because start of the service was attempted too often. See "systemctl status docker.service" …...
2024.2.10 DMS(数据库管理系统)初体验
数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS。它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。用户通过DBMS访问数据库中的数据,数据库管…...
zk集群--集群同步
1.概述 前面一章分析了集群下启动阶段选举过程,一旦完成选举,通过执行QuorumPeer的setPeerState将设置好选举结束后自身的状态。然后,将再次执行QuorumPeer的run的新的一轮循环, QuorumPeer的run的每一轮循环,先判断…...
复习面经哦
1.函数可以变量提升 JavaScript 中的函数存在变量提升的概念,这意味着在执行代码之前,函数声明会被提升到其作用域的顶部。这使得你可以在函数声明之前调用函数。然而,这种行为只适用于函数声明,而不是函数表达式。 下面是一些关…...
c++ STL系列——(二)vector
引言 在现代C编程中,std::vector是最常用的动态数组实现之一,它是C标准模板库(STL)的一部分。vector提供了一种方式,以单一数据结构来存储元素集合,并且可以动态地调整大小以适应新元素。本文将深入探讨ve…...
STM32能够做到数据采集和发送同时进行吗?
STM32能够做到数据采集和发送同时进行吗? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「STM32的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!&am…...
5.Swift常量
Swift 常量 在 Swift 中,除了可以声明变量(使用 var 关键字),还可以声明常量(使用 let 关键字)。常量在赋值后就不能再修改其值,适合用于存储不会改变的数据。以下是关于 Swift 常量的一些重要…...
Linux运行级别 | 管理Linux服务
Linux运行级别 级别: 0关机1单用户2多用户但是不运行nfs网路文件系统3默认的运行级别,给一个黑的屏幕,只能敲命令4未使用5默认的运行级别,图形界面6重启切换运行级别: init x管理Linux服务 systemctl命令…...
Nginx 配置 SSL证书
成功配置SSL证书后,您将能够通过HTTPS加密通道安全访问Nginx服务器。 一、准备材料 SSL证书绑定的域名已完成DNS解析,即您的域名与主机IP地址相互映射。您可以通过DNS验证证书工具,检测域名DNS解析是否生效。具体操作: 【1】登录…...
如何正确理解和获取S参数
S参数是网络参数,定义了反射波和入射波之间的关系,给定频率的S参数矩阵指定端口反射波b的矢量相对于端口入射波a的矢量,如下所示: bS∙a 在此基础上,如下图所示,为一个常见的双端口网络拓扑图:…...
Sping Cloud Hystrix 参数配置、简单使用、DashBoard
Sping Cloud Hystrix 文章目录 Sping Cloud Hystrix一、Hystrix 服务降级二、Hystrix使用示例三、OpenFeign Hystrix四、Hystrix参数HystrixCommand.Setter核心参数Command PropertiesFallback降级配置Circuit Breaker 熔断器配置Metrix 健康统计配置Request Context 相关参数C…...
CSS太极动态图
CSS太极动态图 1. 案例效果 我们今天学习用HTML和CSS实现动态的太极,看一下效果。 2. 分析思路 太极图是由两个旋转的圆组成,一个是黑圆,一个是白圆。实现现原理是使用CSS的动画和渐变背景属性。 首先,为所有元素设置默认值为0…...
TI毫米波雷达开发——High Accuracy Demo 串口数据接收及TLV协议解析 matlab 源码
TI毫米波雷达开发——串口数据接收及TLV协议解析 matlab 源码 前置基础源代码功能说明功能演示视频文件结构01.bin / 02.binParseData.mread_file_and_plot_object_location.mread_serial_port_and_plot_object_location.m函数解析configureSport(comportSnum)readUartCallback…...
基于tomcat运行jenkins常见的报错处理
目录 1.jenkins.util.SystemProperties$Listener错误 升级jdk11可能遇到的坑 2.java.lang.RuntimeException: Fontconfig head is null, check your fonts or fonts configuration 3.There were errors checking the update sites: UnknownHostException:updates.jenkins.i…...
算法学习——LeetCode力扣二叉树篇1
算法学习——LeetCode力扣二叉树篇1 144. 二叉树的前序遍历 144. 二叉树的前序遍历 - 力扣(LeetCode) 描述 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 示例 示例 1: 输入:root [1,null,2,3] 输出&a…...
二叉树的遍历及创建
typedef char T;struct TreeNode {T _data;TreeNode* left;TreeNode* right; }; 1、二叉树的遍历---DFS 3 5 6 …...
图形学:Transform矩阵(3维 2维) 平移,旋转,缩放
0. 简介 在图形学领域中,Transform矩阵(变换矩阵)是一种表示图形对象在二维或三维空间中的位置、方向和大小变化的数学工具。它们用于执行各种图形变换,如平移、旋转、缩放。Transform矩阵通常表示为一个二维或三维矩阵ÿ…...
Docker学习历程
Docker学习历程 Q1、docker还没启动Q2、Docker容器名称冲突的问题Q3:启动minio时发现,容器已经再重启Q4:容器被占用的情况Q5:查看日志 Q1、docker还没启动 docker run --env MODEstandalone --name nacos --restartalways -d -p …...
Android:Volley框架使用
3.15 Volley框架使用 Volley框架主要作为网络请求,图片加载工具。当应用数据量小、网络请求频繁,可以使用Volley框架。 框架Github地址:https://github.com/google/volley Volley框架的简单使用,创建项目Pro_VolleyDemo。将Github上下载Volley框架源代码,volley-master.zi…...
前端修炼手册(uniapp的api篇)
一、页面相关API uni.navigateTo 该API用于跳转到应用内的某个页面,可以传递参数。 uni.navigateTo({url: /pages/detail/detail?id1 })uni.redirectTo 该API用于关闭当前页面并跳转到应用内的某个页面,可以传递参数。 uni.redirectTo({url: /pages/…...
JAVA面试题16
什么是Java中的反射机制?它的用途是什么? 答案:Java的反射机制是指在运行时,通过获取类的信息来操作类的属性、方法和构造函数等。它可以用来创建对象、调用方法,以及实现动态代理等功能。 什么是Java中的泛型&#x…...
P1044 [NOIP2003 普及组] 栈题解
题目 有一个单端封闭的管子,将N(1<N<18)个不同的小球按顺序放入管子的一端。在将小球放入管子的过程中也可以将管子最顶上的一个或者多个小球倒出来。请问:倒出来的方法总数有多少种? 输入输出格式 输入格式 输入文件只含一个整数n…...
【DSP】数字信号处理发展里程碑(AI【文心一言】 辅助生成)
在远离尘嚣的学术殿堂中,数字信号处理(DSP)这一学科犹如一颗璀璨的明珠,其发展历程充满了传奇色彩。下面,就让我们一起穿越时空,回到那些激动人心的时刻,见证数字信号处理从无到有、从弱到强的壮…...
【JavaScript 】finally() 方法和Filter() 方法
JavaScript 中的finally() 方法 finally是 JavaScript 构造中使用的方法try-catch。try它在and阻塞之后执行catch,无论 Promise 是已履行还是已拒绝。该函数的主要作用是执行必要的清理任务并向用户传达消息。一个常见的用例可能是通知用户“您的请求已被处理”&am…...
假期作业8
线程和进程服务器 线程 #include <myhead.h>#define SIP "192.168.0.114" #define SPORT 8888void *task(void *arg){printf("客户端连接\n");sleep(1);pthread_exit(NULL); }int main(int argc, const char *argv[]) {int sfd socket(AF_INET, S…...
基于vue+node.js的校园跳蚤市场系统多商家
校园跳蚤市场系统可以在短时间内完成大量的数据处理、帮助用户快速的查找校园跳蚤市场相关信息,实现的效益更加直观。校园跳蚤市场系统中采用nodejs技术和mysql数据库。主要包括管理员、发布者和用户三大部分,主要功能是实现对个人中心、用户管理、发布者…...
Linux操作系统基础(六):Linux常见命令(一)
文章目录 Linux常见命令 一、命令结构 二、ls命令 三、cd命令 四、mkdir命令 五、touch命令 六、rm命令 七、cp命令 八、mv命令 九、cat命令 十、more命令 Linux常见命令 一、命令结构 command [-options] [parameter]说明: command : 命令名, 相应功能的英文单词…...