基於mupdf的PDF閱讀器
阿新 • • 發佈:2018-11-10
上一篇講了基於poppler庫的PDF閱讀器的開發,這一篇來講基於mupdf的PDF閱讀器的開發。
在上一篇的篇尾我有附效果圖,可以很明顯的看出來這個效果是非常差的,網路上有童鞋同樣遇到了這個問題,並且做了修正,但是,經過測試完全沒用(也可能是版本的問題),所以我不得不做新的嘗試。
-
基於mupdf的PDF閱讀器
同樣的,先要去下載原始碼,進行解壓編譯。mupdf庫比較好的一點是可以很簡單地配置,從而簡化很多不需要的庫,比如我僅僅是需要提取每一個page,然後放大縮小,上一頁、下一頁這種操作,而且是在Qt下做的開發,所以很多庫就不要了,我的配置如下:
make HAVE_X11=no HAVE_GLUT=no prefix=./out install
三十秒不到的時間就編譯完成了,然後在Qt專案中配置庫和標頭檔案就可以進行開發了。在安裝目錄中有一個例子,可以做參考的,可能因為版本問題,例子沒有編過,然而這不是很大的問題,稍作修改就可以了。
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QLabel> #include <QMouseEvent> #include <QScrollArea> #include "mupdf/fitz.h" #include "mupdf/pdf.h" #include <QPointF> #define Max_abs 20 class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); void mouseMoveEvent(QMouseEvent *event); void touchEvent(QTouchEvent *event); void mousePressEvent(QMouseEvent *event); private: float bestFitScale(int pageW, int pageH); void updatePage(); void fz_print_outline(fz_context *ctx, fz_output *out, fz_outline *outline, int level); private: QLabel* label; float scale; int page_number; int page_count; float zoom, rotate; // fz_context *ctx; fz_document *doc; fz_pixmap *pix; QPointF Press_point; public slots: void onPrev(); void onNext(); void onZoomIn(); void onZoomOut(); }; #endif // WIDGET_H
widget.cpp
#include "widget.h" #include <QDebug> #include <QPushButton> Widget::Widget(QWidget *parent) : QWidget(parent) { page_number=0;//第一頁為0 //100%縮放比 zoom=1; //旋轉為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, "Boost程式庫完全開發指南深入C++準標準庫.pdf"); 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; } qDebug() << "page_count: "<< page_count; //get outline fz_outline *outline = fz_load_outline(ctx, (fz_document*)doc); fz_try(ctx) fz_print_outline(ctx, fz_stderr(ctx), outline, 0); fz_always(ctx) fz_drop_outline(ctx, outline); fz_catch(ctx) fz_rethrow(ctx); QScrollArea *LogoArea = new QScrollArea(this); //LogoArea->setGeometry(0, 0, width(), height()); LogoArea->setGeometry(0, 0, 1024, 600); LogoArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); LogoArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); //QWidget *w = new QWidget(LogoArea); //LogoArea->setWidget(w); //QScrollBar* vertScrollBar = LogoArea->verticalScrollBar(); label=new QLabel(this); label->setVisible(false); LogoArea->setWidget(label); LogoArea->setAlignment(Qt::AlignCenter); QPushButton* prevBtn = new QPushButton(this); prevBtn->setText("Prev"); prevBtn->setGeometry(910, 240, 60,100); connect(prevBtn, SIGNAL(pressed()), this, SLOT(onPrev())); QPushButton* nextBtn = new QPushButton(this); nextBtn->setText("Next"); nextBtn->setGeometry(910, 340, 60,100); connect( nextBtn, SIGNAL(pressed()), this, SLOT(onNext())); QPushButton* plusBtn = new QPushButton(this); plusBtn->setText("+"); plusBtn->setGeometry(910, 50, 20, 20); connect( plusBtn, SIGNAL(pressed()), this, SLOT(onZoomIn())); QPushButton* minBtn = new QPushButton(this); minBtn->setText("-"); minBtn->setGeometry(940, 50, 20, 20); connect( minBtn, SIGNAL(pressed()), this, SLOT(onZoomOut())); 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; } //計算縮放以及旋轉 updatePage(); } Widget::~Widget() { } void Widget::mouseMoveEvent(QMouseEvent *event) { qDebug() << event; int xMove; int yMove; xMove = Press_point.x() - event->localPos().x(); yMove = Press_point.y() - event->localPos().y(); event->accept(); } void Widget::mousePressEvent(QMouseEvent *event) { Press_point = event->localPos(); } void Widget::touchEvent(QTouchEvent *event) { qDebug() << event; } float Widget::bestFitScale(int pageW, int pageH) { return ((width() / pageW) > (height() / pageH) ? (height() / pageH) : (width() / pageW)); } void Widget::updatePage() { fz_matrix ctm = fz_scale( zoom, zoom); fz_pre_rotate(ctm, rotate); 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 = pix->samples; int width = fz_pixmap_width(ctx, pix); int height = fz_pixmap_height(ctx, pix); qDebug() << "width: "<<width; qDebug() << "height: "<<height; label->setGeometry(0,0,width,height); label->setAlignment(Qt::AlignCenter); QImage image(samples, width, height,pix->stride,QImage::Format_RGB888); label->setPixmap(QPixmap::fromImage(image)); label->setVisible(true); fz_drop_pixmap(ctx, pix); update(); } void Widget::onPrev() { qDebug() << "onPrev"; page_number--; if(page_number <= 0) page_number = 0; updatePage(); } void Widget::onNext() { qDebug() << "onNext"; page_number++; if(page_number >= page_count -1) page_number = page_count -1; updatePage(); } void Widget::onZoomIn() { zoom += 0.05; updatePage(); } void Widget::onZoomOut() { zoom -= 0.05; updatePage(); } //Tools void Widget::fz_print_outline(fz_context *ctx, fz_output *out, fz_outline *outline, int level) { int i; if(outline == NULL) qDebug()<< "outline is NULL!"; while (outline) { for (i = 0; i < level; i++) // fz_write_printf(ctx, out, "\t"); //fz_write_printf(ctx, out, "%s\t%s\n", outline->title, outline->uri); qDebug()<< outline->title<<" " << outline->uri; if (outline->down) fz_print_outline(ctx, out, outline->down, level + 1); outline = outline->next; } }
效果圖
這個顯示的效果是相當令人滿意的。之前有網友說poppler不能滿足效能,確實如此。