在Qt中调用Mupdf库进行pdf显示

博主因Qt无显示PDF的API,尝试多种库后选择Mupdf。文章详细介绍了在Qt工程中使用Mupdf的步骤,包括下载Mupdf库、编译Mupdf(需修改编译工程设置)、在Qt工程中引入Mupdf静态库,还给出编写代码测试的示例及参考代码链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2018.5.10 更新内存对齐说明

感谢知乎网友@ 孤独子狮 指出QImage处需要考虑内存对齐的问题。因为本人缺乏跨平台、图形库开发经验,所以在调试成功后就没有深入探究。
主要修改了QImage的构造方式,使用了指定bytesPerLine的构造函数,具体原因参见
孤独子狮的回答 - 知乎 https://www.zhihu.com/question/38594052/answer/387891545

前言

最近有个pdf的需求,Qt竟然没有显示pdf的api,着实令人郁闷。之后我尝试用了poppler,但是光配置编译工程就相当麻烦了,没有cmake等开源项目编译经验的人完全一脸懵逼。PDFium也是同理(手头上没有vpn也无法尝试)。感觉Mupdf编译器起来比较简单,所以就来用了一下。不过这个库有个缺点就是编译出来的文件太大了。
本人使用的版本是Mupdf1.12.0+Qt5.9.3+vs2015

下载Mupdf库

https://mupdf.com/downloads/

 

编译Mupdf

在mupdf-1.12.0-source\platform\win32目录下就有现成的mupdf.sln。

这里需要注意:这个工程默认使用的是/MT,而Qt MSVC默认用的是/MD,所以需要修改编译工程设置。我们这里只需要在编译工程中修改就可以了。
以下是一些有关QMake中设置运行库属性 /md /md /mt /mtd 的相关参考
http://blog.csdn.net/caoshangpa/article/details/51416077
http://www.cnblogs.com/codingmylife/archive/2010/05/08/1730832.html
http://www.voidcn.com/article/p-hhosrsia-hq.html

工程里默认生成的是都是静态库,请注意!

根据测试需要的分别是libmupdf.lib、libresources.lib、libthirdparty.lib这三个库(只使用了docs\examples\example.c的代码,使用别的函数可能需要再编译别的工程)
分别修改解决方案中的libmupdf、libthirdparty、libresources这三个工程,将debug下改成/MDd,release下改成/MD,编译即可得到这3个文件。其中libresources只有release版本的,所以debug模式下,我也引用这个文件。

当然你嫌麻烦或者还是不知道该怎么编译,可以去我的github直接下载编译好的静态库。

在Qt工程中引入Mupdf静态库

引入lib文件
新建一个工程,在工程的图标上右键——添加库——外部库。平台只勾选windows,链接选择静态,之后选择对应的库就可以了。(本人将debug与release编译的分别放在debug与release文件夹中)
添加包含目录
将Mupdf目录中的include复制到工程目录下(本人又新建了一个mupdf,将所有文件都放在里面了)
本人是这么写的,具体可以参考源代码:
INCLUDEPATH += $$PWD/mupdf/include/
之后运行QMake。

编写代码进行测试

代码是根据Mupdf中的案例文件example.c中的代码改写

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
#include <QImage>
#include <QPixmap>
#include <QLabel>

#include “mupdf/fitz.h”
#include “mupdf/pdf.h”

Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);

</span><span style="color:#0000ff;">char</span> *input = const_cast&lt; <span style="color:#0000ff;">char</span>* &gt;(<span style="color:#800000;">"</span><span style="color:#800000;">document.pdf</span><span style="color:#800000;">"</span><span style="color:#000000;">);
</span><span style="color:#0000ff;">float</span><span style="color:#000000;"> zoom, rotate;
</span><span style="color:#0000ff;">int</span><span style="color:#000000;"> page_number, page_count;
fz_context </span>*<span style="color:#000000;">ctx;
fz_document </span>*<span style="color:#000000;">doc;
fz_pixmap </span>*<span style="color:#000000;">pix;
fz_matrix ctm;</span><span style="color:#008000;">//</span><span style="color:#008000;">第一页为0</span>
page_number=0<span style="color:#000000;">;
</span><span style="color:#008000;">//</span><span style="color:#008000;">100%缩放比</span>
zoom=<span style="color:#800080;">100</span><span style="color:#000000;">;
</span><span style="color:#008000;">//</span><span style="color:#008000;">旋转为0</span>
rotate=<span style="color:#800080;">0</span><span style="color:#000000;">;

</span><span style="color:#008000;">//</span><span style="color:#008000;">创建上下文</span>
ctx =<span style="color:#000000;"> fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
</span><span style="color:#0000ff;">if</span> (!<span style="color:#000000;">ctx)
{
    qDebug()</span>&lt;&lt;stderr&lt;&lt;<span style="color:#800000;">"</span><span style="color:#800000;">cannot create mupdf context</span><span style="color:#800000;">"</span><span style="color:#000000;">;
    </span><span style="color:#0000ff;">return</span><span style="color:#000000;">;
}

</span><span style="color:#008000;">//</span><span style="color:#008000;">注册文档控制</span>

fz_try(ctx)
fz_register_document_handlers(ctx);
fz_catch(ctx)
{
qDebug()<<stderr<<“cannot register document handlers:”<< fz_caught_message(ctx);
fz_drop_context(ctx);
return;
}

</span><span style="color:#008000;">//</span><span style="color:#008000;">打开文档</span>

fz_try(ctx)
doc = fz_open_document(ctx, input);
fz_catch(ctx)
{
qDebug()<<stderr<< “cannot open document:”<< fz_caught_message(ctx);
fz_drop_context(ctx);
return;
}

</span><span style="color:#008000;">//</span><span style="color:#008000;">取得总的页数</span>

fz_try(ctx)
page_count = fz_count_pages(ctx, doc);
fz_catch(ctx)
{
qDebug()<<stderr<< “cannot count number of pages:”<< fz_caught_message(ctx);
fz_drop_document(ctx, doc);
fz_drop_context(ctx);
return;
}

</span><span style="color:#0000ff;">if</span> (page_number &lt; <span style="color:#800080;">0</span> || page_number &gt;=<span style="color:#000000;"> page_count)
{
    qDebug()</span>&lt;&lt;stderr&lt;&lt; <span style="color:#800000;">"</span><span style="color:#800000;">page number out of range: </span><span style="color:#800000;">"</span>&lt;&lt; page_number + <span style="color:#800080;">1</span>&lt;&lt;<span style="color:#800000;">"</span><span style="color:#800000;">page count:</span><span style="color:#800000;">"</span>&lt;&lt;<span style="color:#000000;">page_count;
    fz_drop_document(ctx, doc);
    fz_drop_context(ctx);
    </span><span style="color:#0000ff;">return</span><span style="color:#000000;">;
}

</span><span style="color:#008000;">//</span><span style="color:#008000;">计算缩放以及旋转</span>
fz_scale(&amp;ctm, zoom / <span style="color:#800080;">100</span>, zoom / <span style="color:#800080;">100</span><span style="color:#000000;">);
fz_pre_rotate(</span>&amp;<span style="color:#000000;">ctm, rotate);

</span><span style="color:#008000;">//</span><span style="color:#008000;">渲染pixmap</span>

fz_try(ctx)
pix = fz_new_pixmap_from_page_number(ctx, doc, page_number, &ctm, fz_device_rgb(ctx), 0);
fz_catch(ctx)
{
qDebug()<<stderr<< “cannot render page: %s\n”<< fz_caught_message(ctx);
fz_drop_document(ctx, doc);
fz_drop_context(ctx);
return;
}

</span><span style="color:#008000;">//</span><span style="color:#008000;">渲染成图片

// unsigned char *samples = fz_pixmap_samples(ctx, pix);
unsigned char *samples = pix->samples;
int width = fz_pixmap_width(ctx, pix);
int height = fz_pixmap_height(ctx, pix);

QImage image(samples, width, height,pix->stride,QImage::Format_RGB888); QLabel *label=new QLabel; label->setPixmap(QPixmap::fromImage(image)); ui->layout->addWidget(label); // if (!image.save(“a.png”)) { // return; // } //回收内存 fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); } Widget::~Widget() { delete ui; }

参考代码 

https://github.com/blueroseslol/QtMupdf

 

找到一个之前有人封装的库,不过经过测试是无法成功编译的,不过可以参考一下mupdf库的用法。
https://github.com/xiangxw/mupdf-qt

别的参考:
http://blog.csdn.net/chenyijun/article/details/42582977

转载于:https://www.cnblogs.com/blueroses/p/8268217.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值