最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Qt 使用Poppler實(shí)現(xiàn)pdf閱讀器的示例代碼

 更新時(shí)間:2018年01月17日 10:31:45   作者:司馬懿字仲達(dá)  
下面小編就為大家分享一篇Qt 使用Poppler實(shí)現(xiàn)pdf閱讀器的示例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

開(kāi)發(fā)環(huán)境 Qt5.5.1、Qt Creator 3.5.1

Qt實(shí)現(xiàn)pdf閱讀器和MFC實(shí)現(xiàn)pdf閱讀器,其實(shí)原理都是差不多的。

需要用到Poppler開(kāi)源庫(kù),下載地址如下 https://poppler.freedesktop.org/

如果只是要在window的gcc下運(yùn)行的話,可以下載已經(jīng)編譯好的庫(kù) https://sourceforge.net/projects/poppler-win32/

 

注意:這個(gè)是MinGW版本的Qt,也就是運(yùn)行在GCC環(huán)境下的庫(kù),里面只包含 *.dll 和 *.a 。如果是Vistual Studio版本的Qt ,那么很不幸里面沒(méi)有 *.lib文件。

1、新建項(xiàng)目,在項(xiàng)目的根目錄新建一個(gè)“poppler”文件夾,將poppler中qt5目錄下的文件都丟進(jìn)去(*.h頭文件,另外再將編譯好的2個(gè)*.a文件和2個(gè)*.dll丟進(jìn)去,我這里多丟了實(shí)現(xiàn)的*.cc文件,因?yàn)?.cc已經(jīng)被編譯成動(dòng)態(tài)庫(kù)了,所以可以不用包含在代碼中)

 

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

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

3、創(chuàng)建pdf工具類(該類負(fù)責(zé)與poppler庫(kù)做對(duì)接,主要負(fù)責(zé)獲取pdf的總頁(yè)數(shù),和每頁(yè)的圖像)

(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();
  //獲取指定頁(yè)pdf圖像(頁(yè)碼從0開(kāi)始)
  QImage getPdfImage(int pageNumber);
  //獲取pdf總頁(yè)碼
  int getNumPages();
  //獲取pdf頁(yè)面大小
  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的右側(cè)顯示滾動(dòng)條,①拖動(dòng)滾動(dòng)條翻頁(yè) ②鼠標(biāo)拖動(dòng)pdf到最上或最底時(shí)翻頁(yè))

注意:本文省略了頁(yè)面緩存,如果是真實(shí)的項(xiàng)目的話,本著嚴(yán)謹(jǐn)?shù)膽B(tài)度,請(qǐng)務(wù)必緩存頁(yè)面

(1)mypdfcanvas.h(繼承父類的resizeEvent是為了 ①當(dāng)pdf只有1頁(yè)時(shí)不顯示滾動(dòng)條 ②當(dāng)用戶拖動(dòng)縮放窗口時(shí)動(dòng)態(tài)改變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);
  //頁(yè)碼從0開(kāi)始
  bool setPage(int pageNumber);
  //獲取頁(yè)數(shù)
  int getNumPages();
  float getScaledRatio();
  //顯示裁剪后的圖片
  bool showClipImage(int pageNumber, int x, int y, int w, int h);
  //取消顯示裁剪圖片,恢復(fù)正常顯示
  void cancelClip();
  //實(shí)際獲取的pdf寬高度
  QSize pdfActualSize;
signals:
  void pageChanged(int currentPage);
private:
  PdfUtils* pdfUtils;
  QString pdfPath;
  //最大緩存圖片數(shù)量
  int maxCachedNum;
  //用來(lái)緩存pdf的每一個(gè)頁(yè)面的圖像(從0開(kāi)始)
  QMap<int, QImage> cachedImageMap;
  //用來(lái)存儲(chǔ)已緩存的pdf頁(yè)面序號(hào)(從0開(kāi)始)
//  QQueue<int> cachedPageQueue;
  //當(dāng)前頁(yè)碼(從0開(kāi)始)
  int currentPage;
  //總頁(yè)碼(從0開(kāi)始)
  int numPages;
  bool isMouseDown;
  int lastMouseY;
  //當(dāng)前pdf頁(yè)面的圖像
  QImage image;
  int imageX;
  int imageY;
  int imageMinY;
  //是否是剪裁狀態(tài)
  bool isClip;
  //獲取指定頁(yè)的圖片
  bool getPdfImage(int pageNumber);
  void reachTop();
  void reachBottom();
  //判斷是否需要發(fā)送重定位簽名框的信號(hào)
  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及右側(cè)滑塊的裝載容器

(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);
  //重新調(diào)整pdf界面大小
  void resizeCanvas();
  void setWidgetVisible(bool pdfCanvasVisible, bool scrollbarVisible);
public slots:
  //當(dāng)拖動(dòng)pdf上滑到頂(或下滑到底)時(shí)觸發(fā)該方法
  onPageChange(int currentPage);
  //當(dāng)滑動(dòng)條的滑塊被滑動(dòng)時(shí),會(huì)調(diào)用該方法
  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、調(diào)用方式

(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、實(shí)際效果圖

 

更新于2016-08-03

8、項(xiàng)目下載地址(使用當(dāng)前最新的庫(kù)poppler-0.45.0、poppler-0.39.0-win32)

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

該項(xiàng)目在win7(Qt5.1)、win10(Qt5.7)下測(cè)試過(guò)了,均可正常運(yùn)行。

下圖為項(xiàng)目目錄中的poppler文件夾(已經(jīng)刪去所有.cc文件),因?yàn)橹挥脦?kù)和頭文件,Qt便可隱式調(diào)用dll中的函數(shù)了。

 

更新于2016-08-22

你們?cè)u(píng)論中遇到的加載庫(kù)的時(shí)候就奔潰現(xiàn)象我還真沒(méi)遇到過(guò)。

下面是測(cè)試情況:

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

 

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

以上這篇Qt 使用Poppler實(shí)現(xiàn)pdf閱讀器的示例代碼就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 一起來(lái)練習(xí)C++的指針

    一起來(lái)練習(xí)C++的指針

    這篇文章主要為大家詳細(xì)介紹了C++的指針,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • c++禁止函數(shù)的傳值調(diào)用的方法

    c++禁止函數(shù)的傳值調(diào)用的方法

    這篇文章主要介紹了c++禁止函數(shù)的傳值調(diào)用的方法,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-08-08
  • C語(yǔ)言零基礎(chǔ)入門(1)

    C語(yǔ)言零基礎(chǔ)入門(1)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言零基礎(chǔ)入門的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • C語(yǔ)言?typedef的用法示例詳解

    C語(yǔ)言?typedef的用法示例詳解

    typedef是在C和C++編程語(yǔ)言中的一個(gè)關(guān)鍵字,作用是為現(xiàn)有的數(shù)據(jù)類型(int、float、char……)創(chuàng)建一個(gè)新的名字,目的是為了使代碼方便閱讀和理解,這篇文章主要介紹了C語(yǔ)言typedef的使用,需要的朋友可以參考下
    2023-06-06
  • c語(yǔ)言中abs()和fabs()的區(qū)別點(diǎn)整理

    c語(yǔ)言中abs()和fabs()的區(qū)別點(diǎn)整理

    在本篇文章里小編給大家分享的是關(guān)于c語(yǔ)言abs()和fabs()的區(qū)別,有需要的朋友們可以參考學(xué)習(xí)下。
    2020-02-02
  • c++函數(shù)指針和回調(diào)函數(shù)示例

    c++函數(shù)指針和回調(diào)函數(shù)示例

    這篇文章主要介紹了c++函數(shù)指針和回調(diào)函數(shù)示例,需要的朋友可以參考下
    2014-05-05
  • C++實(shí)現(xiàn)圖像目標(biāo)區(qū)裁剪ImageCropping

    C++實(shí)現(xiàn)圖像目標(biāo)區(qū)裁剪ImageCropping

    本文主要介紹了C++實(shí)現(xiàn)圖像目標(biāo)區(qū)裁剪ImageCropping,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C++實(shí)現(xiàn)線性表鏈?zhǔn)酱鎯?chǔ)(單鏈)

    C++實(shí)現(xiàn)線性表鏈?zhǔn)酱鎯?chǔ)(單鏈)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)線性表鏈?zhǔn)酱鎯?chǔ),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • C語(yǔ)言實(shí)現(xiàn)掃雷游戲(初級(jí)版)

    C語(yǔ)言實(shí)現(xiàn)掃雷游戲(初級(jí)版)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷游戲初級(jí)版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之棧和隊(duì)列的實(shí)現(xiàn)及應(yīng)用

    C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之棧和隊(duì)列的實(shí)現(xiàn)及應(yīng)用

    棧和隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),只規(guī)定了性質(zhì),并沒(méi)有規(guī)定實(shí)現(xiàn)方式。本文將以順序結(jié)構(gòu)實(shí)現(xiàn)棧,鏈表方式實(shí)現(xiàn)隊(duì)列,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧
    2022-08-08

最新評(píng)論

望谟县| 古田县| 惠来县| 德兴市| 瑞昌市| 高唐县| 万州区| 孟村| 余姚市| 黔江区| 兴业县| 资源县| 秦安县| 红桥区| 固安县| 堆龙德庆县| 宜黄县| 昌乐县| 璧山县| 南通市| 华安县| 望奎县| 手游| 理塘县| 黄梅县| 南平市| 凤山市| 方城县| 宁安市| 宜君县| 宜黄县| 武胜县| 闽侯县| 建平县| 镇原县| 宜都市| 涿州市| 垦利县| 霍林郭勒市| 乌拉特中旗| 达日县|