基于mupdf的PDF阅读器

上一篇讲了基于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不能满足性能,确实如此。

猜你喜欢

转载自blog.csdn.net/k_wang_/article/details/82870401