亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

Qt 使用Poppler實現pdf閱讀器的示例代碼

2020-01-26 13:48:09
字體:
來源:轉載
供稿:網友

開發環境 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/

 

注意:這個是MinGW版本的Qt,也就是運行在GCC環境下的庫,里面只包含 *.dll 和 *.a 。如果是Vistual Studio版本的Qt ,那么很不幸里面沒有 *.lib文件。

1、新建項目,在項目的根目錄新建一個“poppler”文件夾,將poppler中qt5目錄下的文件都丟進去(*.h頭文件,另外再將編譯好的2個*.a文件和2個*.dll丟進去,我這里多丟了實現的*.cc文件,因為*.cc已經被編譯成動態庫了,所以可以不用包含在代碼中)

 

2、在項目的pro配置文件中添加以下內容,引用poppler的頭文件和庫文件(注意:我這里是win32,所以前面加了win32前綴)

INCLUDEPATH += $$PWD/popplerwin32: LIBS += -L$$PWD/poppler -llibpopplerwin32: 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, -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_OBJECTpublic:  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 x, int y, int w, 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 30class MainWindow : public QMainWindow{  Q_OBJECTpublic:  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)), this, 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, 0, this->width()-SCROLLBAR_WIDTH, this->height());    scrollbar->setGeometry(this->width()-SCROLLBAR_WIDTH, 0, 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、實際效果圖

 

更新于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中的函數了。

 

更新于2016-08-22

你們評論中遇到的加載庫的時候就奔潰現象我還真沒遇到過。

下面是測試情況:

(1)當PDF文件未找到的情況,會輸出錯誤日志,但是并不會崩潰。

 

(2)當路徑中包含”中文“,且包含"空格"的情況,poppler是可以正常打開的。

以上這篇Qt 使用Poppler實現pdf閱讀器的示例代碼就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美精品videosex性欧美| 欧美精品videossex88| 国产精品无码专区在线观看| 午夜精品一区二区三区在线播放| 国产精品午夜一区二区欲梦| 亚洲欧美色图片| 国产精品你懂得| 欧美大片大片在线播放| 日本成人免费在线| 欧美午夜xxx| 欧美日韩免费观看中文| 成人乱人伦精品视频在线观看| 欧美视频免费在线| 日韩女优人人人人射在线视频| 色综合久综合久久综合久鬼88| 日韩在线欧美在线| 日本成人黄色片| 日韩精品在线视频| 亚洲欧美日韩一区二区在线| 国产精品美女www爽爽爽视频| 91亚洲精品久久久| 欧美不卡视频一区发布| 国产成人精品午夜| 欧美精品videos另类日本| 久久久久久久一| 91精品免费久久久久久久久| 日韩经典中文字幕| 日韩精品高清视频| 热久久这里只有精品| 青青久久aⅴ北条麻妃| 狠狠躁夜夜躁人人爽天天天天97| 在线视频日本亚洲性| 日本精品va在线观看| 国产欧美日韩免费| 久久精品视频在线| 国产日韩一区在线| 久久久精品国产亚洲| 欧美日韩国产中文字幕| 国产精品无av码在线观看| 欧美成人全部免费| 国产欧美亚洲视频| 国内自拍欧美激情| 国产精品美女网站| 日韩精品中文字幕在线播放| 88xx成人精品| 欧美国产极速在线| 亚洲一区二区三| 国产香蕉97碰碰久久人人| 色婷婷综合久久久久| 亚洲激情在线视频| 亚洲视频欧洲视频| 国产精品电影在线观看| 久久精品国产精品亚洲| 中文字幕久精品免费视频| 亚洲精品视频中文字幕| zzjj国产精品一区二区| 国产欧亚日韩视频| 欧美亚洲国产另类| 日韩中文字幕视频在线观看| 色综合视频一区中文字幕| 日韩av电影国产| 庆余年2免费日韩剧观看大牛| 欧美亚洲国产日本| 国产精品96久久久久久又黄又硬| 亚洲片av在线| 国产在线观看不卡| 97免费视频在线播放| 成人久久久久久| 久久久久久香蕉网| 欧美成人高清视频| 国产视频综合在线| 亚洲肉体裸体xxxx137| 91福利视频在线观看| 亚洲美女视频网站| 不卡在线观看电视剧完整版| 亚洲最大在线视频| 国产日韩综合一区二区性色av| 91性高湖久久久久久久久_久久99| 久久久免费高清电视剧观看| 亚洲精品视频在线观看视频| 国产精品久久久久一区二区| 国产精品青草久久久久福利99| 欧美激情中文网| 国产精品麻豆va在线播放| 亚洲精品一区二区网址| 日韩中文字幕av| 92国产精品久久久久首页| 欧美成在线观看| 国产精品xxxxx| 中文字幕亚洲激情| 深夜福利日韩在线看| 2020国产精品视频| 美女扒开尿口让男人操亚洲视频网站| 欧美性xxxx在线播放| 91久久精品日日躁夜夜躁国产| 国产欧亚日韩视频| 久久成人综合视频| 97视频免费观看| 欧美区二区三区| 国产精品久久久久77777| 成人免费淫片aa视频免费| 日韩专区在线播放| 日本亚洲欧美三级| 欧美在线视频一区二区| 亚洲欧美日韩精品久久奇米色影视| 欧美激情va永久在线播放| 国产精品网站大全| 精品无人区太爽高潮在线播放| 久久国产精品99国产精| 国产精品色午夜在线观看| 中文字幕最新精品| 亚洲精品二三区| 欧美成人黄色小视频| 中文字幕亚洲综合久久筱田步美| 91精品久久久久久综合乱菊| 在线一区二区日韩| 日韩欧美中文字幕在线观看| 久久精品99久久久久久久久| 久久久精品999| 日韩av手机在线| www.亚洲天堂| 91沈先生在线观看| 91精品国产综合久久香蕉最新版| 久久久久久国产精品三级玉女聊斋| 日韩成人激情在线| 国产精品极品尤物在线观看| 日韩av电影手机在线观看| 亚洲成人在线视频播放| 97激碰免费视频| 亚洲一区二区三区xxx视频| 日韩日本欧美亚洲| 在线观看国产精品日韩av| 国产精品久久久久久av| 国产在线拍揄自揄视频不卡99| 久久久久久国产精品三级玉女聊斋| 亚洲一区二区三区sesese| 成人免费黄色网| 日韩小视频在线| 国语自产精品视频在线看| 欧洲日本亚洲国产区| 日韩视频亚洲视频| 按摩亚洲人久久| 国产精品成人品| 成人黄色av网| 美日韩丰满少妇在线观看| 国产亚洲精品久久| 欧美洲成人男女午夜视频| 精品国产乱码久久久久久虫虫漫画| www高清在线视频日韩欧美| 中文字幕精品www乱入免费视频| 最近2019中文免费高清视频观看www99| 亚洲国产日韩欧美在线图片| 91干在线观看| 日韩中文字幕国产精品| www.欧美三级电影.com| 欧美老少做受xxxx高潮| 日本一欧美一欧美一亚洲视频| 久久久成人精品| 国产亚洲欧美视频| 欧美人在线观看| 国产成人精品亚洲精品| 国产网站欧美日韩免费精品在线观看| 久久久之久亚州精品露出| 久久久久一本一区二区青青蜜月|