程序笔记   发布时间:2022-06-07  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Qt 使用Poppler实现pdf阅读器的示例代码大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

开发环境 Qt5.5.1、Qt Creator 3.5.1

Qt实现pdf阅读器和MFC实现pdf阅读器,其实原理都是差不多的。

需要用到Poppler开源库,下载地址如下 https://poppler.freedesktop.org/

如果只是要在window的gcc下运行的话,可以下载已经编译好的库 https://sourceforge.net/projects/poppler-win32/

Qt 使用Poppler实现pdf阅读器的示例代码

 

注意:这个是MinGW版本的Qt,也就是运行在GCC环境下的库,里面只包含 *.dll 和 *.a 。如果是Vistual studio版本的Qt ,那么很不幸里面没有 *.lib文件。

1、新建项目,在项目的根目录新建一个“poppler”文件夹,将poppler中qt5目录下的文件都丢进去(*.h头文件,另外再将编译好的2个*.a文件和2个*.dll丢进去,我这里多丢了实现的*.cc文件,因为*.cc已经被编译成动态库了,所以可以不用包含在代码中)

Qt 使用Poppler实现pdf阅读器的示例代码

 

2、在项目的pro配置文件中添加以下内容,引用poppler的头文件和库文件(注意:我这里是win32,所以前面加了win32前缀)

INCLUDEPATH += $$PWD/poppler
win32: liBS += -L$$PWD/poppler -llibpoppler
win32: liBS += -L$$PWD/poppler -llibpoppler-qt5

3、创建pdf工具类(该类负责与poppler库做对接,主要负责获取pdf的总页数,和每页的图像)

(1)pdfutils.h

#ifndef pdfUTILS_H
#define pdfUTILS_H
#include <QObject>
#include <QImage>
#include <QSize>
#include <QDeBUG>
#include "poppler-qt5.h"
class pdfUtils
{
public:
  explicit pdfUtils(QString filePath);
  ~pdfUtils();
  //获取指定页pdf图像(页码从0开始)
  QImage getpdfImage(int pagenumber);
  //获取pdf总页码
  int getNumPages();
  //获取pdf页面大小
  QSize getPageSize();
private:
  QString filePath;
  int numPages;
  QSize pageSize;
  voID getpdfInfo();
};
#endif // pdfUTILS_H

(2)pdfutils.cpp

#include "pdfutils.h"
pdfUtils::pdfUtils(QString filePath) {
  this->filePath = filePath;
  getpdfInfo();
}
pdfUtils::~pdfUtils() {
}
QImage pdfUtils::getpdfImage(int pagenumber) {
  QImage image;
  Poppler::document* document = Poppler::document::load(filePath);
  if (!document || document->isLocked()) {
    // ... error message ....
    delete document;
    return image;
  }
  // document starts at page 0
  Poppler::Page* pdfpage = document->page(pagenumber);
  if (pdfpage == 0) {
    // ... error message ...
    return image;
  }
  // Generate a QImage of the rendered page
  image = pdfpage->renderToImage(72,72,-1,-1);
  if (image.isNull()) {
    // ... error message ...
    return image;
  }
  // after the usage,the page must be deleted
  delete pdfpage;
  delete document;
  return image;
}
int pdfUtils::getNumPages() {
  return numPages;
}
QSize pdfUtils::getPageSize() {
  return pageSize;
}
voID pdfUtils::getpdfInfo() {
  numPages = 0;
  Poppler::document* document = Poppler::document::load(filePath);
  if (!document || document->isLocked()) {
    // ... error message ....
    delete document;
    return;
  }
  numPages = document->numPages();
  Poppler::Page* pdfpage = document->page(0);
  pageSize = pdfpage->pageSize();
  qDeBUG()<<pageSize;
  delete pdfpage;
  delete document;
}

4、pdf显示类(pdf的右侧显示滚动条,①拖动滚动条翻页 ②鼠标拖动pdf到最上或最底时翻页)

注意:本文省略了页面缓存,如果是真实的项目的话,本着严谨的态度,请务必缓存页面

(1)mypdfcanvas.h(继承父类的resizeEvent是为了 ①当pdf只有1页时不显示滚动条 ②当用户拖动缩放窗口时动态改变pdf显示尺寸)

#ifndef MYPdfcANVAS_H
#define MYPdfcANVAS_H
#include <QWidget>
#include <QVector>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QPainter>
#include <QPaintEvent>
#include <QMap>
#include <QPalette>
#include <QResizeEvent>
#include "pdfutils.h"
class MyPdfcanvas : public QWidget
{
  Q_OBjeCT
public:
  explicit MyPdfcanvas(QWidget *parent = 0);
  ~MyPdfcanvas();
  voID resizeEvent(QResizeEvent* E);
  voID paintEvent(QPaintEvent *E);
  voID mousepressEvent(QMouseEvent *E);
  voID mouseReleaseEvent(QMouseEvent *E);
  voID mouseMoveEvent(QMouseEvent *E);
  voID setMaxCachednum(int maxCachednum);
  //如果不能解析pdf返回false
  bool setPath(QString pdfPath);
  //页码从0开始
  bool setPage(int pagenumber);
  //获取页数
  int getNumPages();
  float getScaledratio();
  //显示裁剪后的图片
  bool showClipImage(int pagenumber,int x,int y,int w,int h);
  //取消显示裁剪图片,恢复正常显示
  voID cancelClip();
  //实际获取的pdf宽高度
  QSize pdfActualSize;
signals:
  voID pageChanged(int currentPagE);
private:
  pdfUtils* pdfUtils;
  QString pdfPath;
  //最大缓存图片数量
  int maxCachednum;
  //用来缓存pdf的每一个页面的图像(从0开始)
  QMap<int,QImage> cachedImageMap;
  //用来存储已缓存的pdf页面序号(从0开始)
//  QQueue<int> cachedPageQueue;
  //当前页码(从0开始)
  int currentPage;
  //总页码(从0开始)
  int numPages;
  bool isMouseDown;
  int lastMouseY;
  //当前pdf页面的图像
  QImage image;
  int imageX;
  int imageY;
  int imageMinY;
  //是否是剪裁状态
  bool isClip;
  //获取指定页的图片
  bool getpdfImage(int pagenumber);
  voID reachtop();
  voID reachBottom();
  //判断是否需要发送重定位签名框的信号
  voID needLocateSignArea();
};
#endif // MYPdfcANVAS_H

(2)pdfcanvas.cpp

#include "mypdfcanvas.h"
MyPdfcanvas::MyPdfcanvas(QWidget *parent) : QWidget(parent) {
  pdfUtils = NulL;
  imageX = 0;
  imageY = 0;
  isClip = false;
  setautoFillBACkground(true);
}
MyPdfcanvas::~MyPdfcanvas() {
  if(pdfUtils != NulL) delete pdfUtils;
}
voID MyPdfcanvas::resizeEvent(QResizeEvent *E) {
  image = this->cachedImageMap[currentPage];
  if(!image.isNull()) {
    float radio = (float)e->size().wIDth()/(float)e->oldSize().wIDth();
    int imageHeight = image.height()* e->size().wIDth()/image.wIDth();
    image = image.scaled(e->size().wIDth(),imageHeight);
    if(imageHeight < this->height()) {
      imageY = (this->height()-imageHeight)/2;
      //如果图片高度小于控件高度,则图片居中
//      imageMinY = imageY;
      imageMinY = 0;
      imageY = imageMinY;
    } else {
      if(radio>0) {
        imageY = (int)(imageY*radio);
        if(imageY > 0) {
          imageY = 0;
        }
      } else {
        imageY = 0;
      }
    }
  }
}
voID MyPdfcanvas::paintEvent(QPaintEvent *E) {
  QPainter* painter = new QPainter(this);
  if(image.isNull()) {
    painter->fillRect(this->rect(),Qt::transparent);
    return;
  }
  painter->drawImage(0,imageY,imagE);
  delete painter;
}
voID MyPdfcanvas::mousepressEvent(QMouseEvent *E) {
  isMouseDown = true;
  lastMouseY = e->y();
}
voID MyPdfcanvas::mouseReleaseEvent(QMouseEvent *E){
  isMouseDown = false;
}
voID MyPdfcanvas::mouseMoveEvent(QMouseEvent *E){
  if(!isMouseDown || image.isNull()) {
    return;
  }
  int distance = e->y() - lastMouseY;
  lastMouseY = e->y();
  imageY += distance;
  if(imageY > 0) {
    imageY = 0;
    reachtop();
    return;
  } else if(imageY < imageMinY) {
    imageY = imageMinY;
    reachBottom();
    return;
  }
  update();
}
voID MyPdfcanvas::setMaxCachednum(int maxCachednum) {
  this->maxCachednum = maxCachednum;
}
bool MyPdfcanvas::setPath(QString pdfPath) {
  this->pdfPath = pdfPath;
  if(pdfUtils != NulL) delete pdfUtils;
  pdfUtils = new pdfUtils(pdfPath);
  numPages = pdfUtils->getNumPages();
  if(numPages > 0) {
    isClip = false;
    pdfActualSize = pdfUtils->getPageSize();
  }
  cachedImageMap.clear();
  currentPage = 0;
  imageY = 0;
  lastMouseY = 0;
  return numPages > 0;
}
bool MyPdfcanvas::setPage(int pagenumber) {
  if(!getpdfImage(pagenumber)) {
    return false;
  }
  isClip = false;
  isMouseDown = false;
  image = image.scaledToWIDth(this->wIDth());
  imageMinY = this->height() - image.height();
  if(image.height() < this->height()) {
    //如果图片高度小于控件高度,则图片居中
//    imageMinY /= 2;
    imageMinY = 0;
    imageY = imageMinY;
  } else {
    imageY = 0;
  }
  update();
  return true;
}
int MyPdfcanvas::getNumPages() {
  return numPages;
}
float MyPdfcanvas::getScaledratio() {
  int pdfWIDth = pdfUtils->getPageSize().wIDth();
  return (float)this->wIDth()/(float)pdfWIDth;
}
bool MyPdfcanvas::showClipImage(int pagenumber,int h) {
  if(!getpdfImage(pagenumber)) {
    return false;
  }
  isClip = true;
  imageY = 0;
  image = image.copy(x,y,w,h).scaled(this->size());
  update();
}
voID MyPdfcanvas::cancelClip() {
  isClip = false;
  setPage(currentPagE);
}
bool MyPdfcanvas::getpdfImage(int pagenumber) {
  if(pagenumber<0 || pagenumber >= numPages) {
    return false;
  }
  if(cachedImageMap.contains(pagenumber)) {
    image = cachedImageMap.value(pagenumber);
  } else {
    image = pdfUtils->getpdfImage(pagenumber);
    if(!image.isNull()) {
      cachedImageMap[pagenumber] = image;
      pdfActualSize = image.size();
    }
  }
  if(image.isNull()) {
    return false;
  }
  currentPage = pagenumber;
  return true;
}
voID MyPdfcanvas::reachtop() {
  if(currentPage > 0) {
    emit pageChanged(currentPage-1);
  }
}
voID MyPdfcanvas::reachBottom() {
  if(currentPage < numPages-1) {
    emit pageChanged(currentPage+1);
  }
}

5、pdf及右侧滑块的装载容器

(1)mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QScrollbar>
#include "mypdfcanvas.h"
#define SCRolLbar_WIDTH 30
class MainWindow : public QMainWindow
{
  Q_OBjeCT
public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();
  voID resizeEvent(QResizeEvent* E);
  bool setpdfPath(QString path);
  //重新调整pdf界面大小
  voID resizeCanvas();
  voID setWidgetVisible(bool pdfcanvasVisible,bool scrollbarVisiblE);
public slots:
  //当拖动pdf上滑到顶(或下滑到底)时触发该方法
  onPageChange(int currentPagE);
  //当滑动条的滑块被滑动时,会调用该方法
  onScrollbarValueChange();
private:
  MyPdfcanvas *pdfcanvas;
  QScrollbar *scrollbar;
};
#endif // MAINWINDOW_H

(2)mainwindow.cpp

#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
  pdfcanvas = new MyPdfcanvas(this);
  scrollbar = new QScrollbar(Qt::Vertical,this);
  setWidgetVisible(false,falsE);
  connect(pdfcanvas,SIGNAL(pageChanged(int)),this,SLOT(onPageChange(int)));
  connect(scrollbar,SIGNAL(valueChanged(int)),SLOT(onScrollbarValueChange()));
}
MainWindow::~MainWindow() {
}
voID MainWindow::resizeEvent(QResizeEvent *E) {
  resizeCanvas();
}
bool MainWindow::setpdfPath(QString path) {
  bool result = pdfcanvas->setPath(path);
  if(result) {
    int numPages = pdfcanvas->getNumPages();
    if(numPages>1) {
      scrollbar->setMaximum(numPages-1);
      scrollbar->SETVALue(0);
    }
    pdfcanvas->setPage(0);
  }
  resizeCanvas();
  return result;
}
voID MainWindow::resizeCanvas() {
  qDeBUG()<<"resize "<<this->rect()<<","<<pdfcanvas->rect();
  int numPages = pdfcanvas->getNumPages();
  if(numPages == 1) {
    pdfcanvas->setGeometry(this->rect());
    setWidgetVisible(true,falsE);
  } else if(numPages > 1) {
    pdfcanvas->setGeometry(0,this->wIDth()-SCRolLbar_WIDTH,this->height());
    scrollbar->setGeometry(this->wIDth()-SCRolLbar_WIDTH,this->height());
    setWidgetVisible(true,truE);
  } else {
    //numPages <= 0
    setWidgetVisible(false,falsE);
  }
}
voID MainWindow::setWidgetVisible(bool pdfcanvasVisible,bool scrollbarVisiblE) {
  pdfcanvas->setVisible(pdfcanvasVisiblE);
  scrollbar->setVisible(scrollbarVisiblE);
}
MainWindow::onPageChange(int currentPagE) {
  pdfcanvas->setPage(currentPagE);
}
MainWindow::onScrollbarValueChange() {
  pdfcanvas->setPage(scrollbar->value());
}

6、调用方式

(1)main.cpp

#include "mainwindow.h"
#include <QApplication>
int main(int argc,char *argv[])
{
  QApplication a(argc,argv);
  MainWindow w;
  w.resize(500,500);
  w.show();
  QString path = "D://test.pdf";
  w.setpdfPath(path);
  w.setwindowtitle(path);
  return a.exec();
}

7、实际效果图

Qt 使用Poppler实现pdf阅读器的示例代码

 

更新于2016-08-03

8、项目下载地址(使用当前最新的库poppler-0.45.0、poppler-0.39.0-win32)

http://download.csdn.net/detail/chy555chy/9593364

该项目在win7(Qt5.1)、win10(Qt5.7)下测试过了,均可正常运行。

下图为项目目录中的poppler文件夹(已经删去所有.cc文件),因为只用库和头文件,Qt便可隐式调用dll中的函数了。

Qt 使用Poppler实现pdf阅读器的示例代码

 

更新于2016-08-22

你们评论中遇到的加载库的时候就奔溃现象我还真没遇到过。

下面是测试情况:

(1)当pdf文件未找到的情况,会输出错误日志,但是并不会崩溃。

Qt 使用Poppler实现pdf阅读器的示例代码

 

(2)当路径中包含”中文“,且包含"空格"的情况,poppler是可以正常打开的。

Qt 使用Poppler实现pdf阅读器的示例代码

以上这篇Qt 使用Poppler实现pdf阅读器的示例代码就是小编分享给大家的全部内容了,希望能给大家一个参,也希望大家多多支持编程小技巧。

大佬总结

以上是大佬教程为你收集整理的Qt 使用Poppler实现pdf阅读器的示例代码全部内容,希望文章能够帮你解决Qt 使用Poppler实现pdf阅读器的示例代码所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。