在Qt中調用Mupdf庫進行pdf顯示


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);

    char *input = const_cast< char* >("document.pdf");
    float zoom, rotate;
    int page_number, page_count;
    fz_context *ctx;
    fz_document *doc;
    fz_pixmap *pix;
    fz_matrix ctm;//第一頁為0
    page_number=0;
    //100%縮放比
    zoom=100;
    //旋轉為0
    rotate=0;

    //創建上下文
    ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
    if (!ctx)
    {
        qDebug()<<stderr<<"cannot create mupdf context";
        return;
    }

    //注冊文檔控制
    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;
    }

    //打開文檔
    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;
    }

    //取得總的頁數
    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;
    }

    if (page_number < 0 || page_number >= page_count)
    {
        qDebug()<<stderr<< "page number out of range: "<< page_number + 1<<"page count:"<<page_count;
        fz_drop_document(ctx, doc);
        fz_drop_context(ctx);
        return;
    }

    //計算縮放以及旋轉
    fz_scale(&ctm, zoom / 100, zoom / 100);
    fz_pre_rotate(&ctm, rotate);

    //渲染pixmap
    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;
    }

    //渲染成圖片
//   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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM