qt用c语言编程 pdf下载文件,Qt 使用Poppler实现pdf阅读器的示例代码

开发环境 Qt5.5.1、Qt Creator 3.5.1

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

b3772e68ed43b5d4376c4ae780a92238.png

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

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

082da10c50849db3360d8bd41afb6ff2.png

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

#include

#include

#include

#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()<

delete pdfPage;

delete document;

}

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

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

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

#ifndef MYPDFCANVAS_H

#define MYPDFCANVAS_H

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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 cachedImageMap;

//用来存储已缓存的pdf页面序号(从0开始)

// QQueue 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

#include

#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)), 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()<rect()<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

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、实际效果图

99050ec404ead8cabd985e3d79669b8c.gif

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

126234770c5a894c7de1d351a39c220e.png

更新于2016-08-22

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

下面是测试情况:

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

b857697a37f8dde757680b6bd5c0aeac.png

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

f72749dcf786ec76c1652fb84e242a7c.png

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言工厂方法模式,工厂函数模式 (C语言实现)

工厂模式属于创建型模式&#xff0c;大致可以分为三类&#xff0c;简单工厂模式、工厂方法模式、抽象工厂模式。二. 工厂方法模式所谓工厂方法模式&#xff0c;是指定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子…

光绘文件 c语言 解析,AltiumDesigner输出光绘文件

1、钻孔信息生成设置打开PCB文件&#xff0c;放置钻孔位图符号对应的孔大小的列表&#xff1a;切换到DrillDrawing层放置字符串&#xff0c;Place->string(PS)&#xff0c;此时按Tab键&#xff0c;在出现的Text文本框中点击下拉箭头&#xff0c;选择.Legend&#xff0c;OK。…

曼哈顿距离最小生成树与莫队算法(总结)

曼哈顿距离最小生成树与莫队算法&#xff08;总结&#xff09; 1 曼哈顿距离最小生成树 曼哈顿距离最小生成树问题可以简述如下&#xff1a; 给定二维平面上的N个点&#xff0c;在两点之间连边的代价为其曼哈顿距离&#xff0c;求使所有点连通的最小代价。 朴素的算法可以用O(N…

功能引导 android,Flutter实现App功能引导页

App功能介绍页&#xff0c;主要是由介绍app功能的几张图片和当前页指示符组成&#xff0c;如下效果我们来一步一步实现上面的界面,左右滑动切换显示功能页,这个可以通过PageView来实现,底部的指示符半透明覆盖在PageView上,开发过Android同学知道可以用Framelayout布局来实现&a…

ocp oracle 考试报名_获得Oracle认证对拓展职业前景的影响

知识就是力量通过考试和考试成绩固然很重要&#xff0c;但您在学习过程中所掌握的知识才是您职业成功的坚实基础。在备考过程中&#xff0c;获得的知识和经验才是您真正的财富。Oracle Certified Associate (OCA)&#xff1a;专员级别的认证能够证明学员具备基本技能&#xff0…

mac android 录屏软件下载,苹果录屏app下载 苹果录屏 for Android V2.1.3 安卓手机版 下载-脚本之家...

苹果录屏是一款不错的手机录屏软件&#xff0c;该软件能帮助你录制流畅清晰视频&#xff0c;实现屏幕内容实时同步录制&#xff0c;录制视频流畅清晰不卡顿&#xff0c;需要的朋友可以下载使用。应用介绍苹果录屏&#xff0c;是一款免费屏幕录制软件&#xff0c;能帮助你录制流…

火箭技术术语_仿真优化火箭发动机 3D 打印制造工艺

台湾工业技术研究院(ITRI)为台湾创新空间(TiSPACE)提供增材制造(也称 3D 打印技术)服务&#xff0c;包括原始设计制造、重新设计和仿真等。TiSPACE 的固液火箭发动机中使用的燃料喷射器组件的 3D 打印过程为&#xff1a;首先&#xff0c;激光将第一层粉末熔化并融合到构建板上&…

车林通购车之家--购车计算器模块--保险

//car-calculator-bx.twig {{ include(jsq-nav.twig) }} <div class"switch-item active" id"bodya"><div class"top-layer2 clearfix"><div class"tit"><span>新车保险市场价</span></div><…

麒麟710f能否升级到鸿蒙系统,定了!麒麟710以上支持升级鸿蒙系统,荣耀也可以升级...

原标题&#xff1a;定了&#xff01;麒麟710以上支持升级鸿蒙系统&#xff0c;荣耀也可以升级华为Mate X2发布会上&#xff0c;余承东表示4月份推送手机版鸿蒙系统&#xff0c;距离首发日期越来越近。不少朋友关心&#xff0c;哪些机型支持鸿蒙系统&#xff0c;荣耀手机可以更新…

android5.1.1移植教程,iTOP4412开发板Android5.1.1移植教程

对于传统的操作系统来说&#xff0c;普通的 I/O 操作一般会被内核缓存&#xff0c;这种 I/O 被称作缓存 I/O。本文所介绍的文件访问机制不经过操作系统内核的缓存&#xff0c;数据直接在磁盘和应用程序地址空间进行传输&#xff0c;所以该文件访问的机制称作为直接 I/O。Linux …

岗位po是什么意思_劳务派遣是什么意思,劳务派遣和正式员工区别在哪

劳务派遣也是劳动活动的一种&#xff0c;虽然性质相对于临时工&#xff0c;但是劳务派遣仍然属于劳动合同法所调整的&#xff0c;不过与正式员工存在一定区别。因此接下来将由找法网小编为您介绍关于劳务派遣是什么意思&#xff0c;劳务派遣和正式员工区别在哪及其相关方面的知…

Android对性能要求,Android性能管理

管理Android设备的功耗和性能有助于确保应用程序在各种硬件上始终如一地顺畅运行。在Android 7.0及更高版本中&#xff0c;OEM可以实现对持续性能提示的支持&#xff0c;使应用程序能够保持一致的设备性能&#xff0c;并指定专属核以提高CPU密集型前台应用程序的性能。持续性能…

layui导航栏页面滚动固定_帮你搞定长滚动网页的设计!这5种设计策略需谨记!...

网站中的内容再好&#xff0c;总得让用户能看到&#xff0c;才有价值&#xff0c;而矛盾在于&#xff0c;首屏的空间始终是有限的。所以&#xff0c;我们总希望用户能够滚动页面向下看&#xff0c;从某种意义上来说&#xff0c;长滚动页面和无限滚动的设计&#xff0c;如此地受…

南邮计算机专硕考研专业课,南京邮电大学(专业学位)计算机技术研究生考试科目和考研参考书目...

考研真题资料优惠价原价选择南京邮电大学(专业学位)计算机技术教材&#xff0c;也叫南京邮电大学(专业学位)计算机技术考研参考书、指定书目等等&#xff0c;是考验专业课复习过程中最重要的资料。考研是一种针对性很强的考试项目&#xff0c;参考书目由报考院校的研究生院制定…

ios 设置属性的center_【从0到1的Stata图表学习1】图例设置

导读规则&#xff1a;正文出现非加粗红色字体&#xff0c;对应Stata命令&#xff1b;正文中出现蓝色字体&#xff0c;对应往期链接&#xff1b;do文件中&#xff1a;"/**/"符号代表作者注释内容&#xff0c;帮助理解&#xff1b;"//"代表分节&#xff0c;便…

计算机网络的应用领域有那些,计算机网络应用领域

描述计算机网络应用领域一、计算机网络在现代企业中的应用计算机网络的发展和应用改变了传统企业的管理模式和经营模式。在现代企业中企业信息网络得到了广泛的应用。它是一种专门用于企业内部信息管理的计算机网络&#xff0c;覆盖企业生产经营管理的各个部门&#xff0c;在整…

ffmpeg rtsp转hls_Qt音视频开发24-ffmpeg音视频同步

## 一、前言用ffmpeg来做音视频同步&#xff0c;个人认为这个是ffmpeg基础处理中最难的一个&#xff0c;无数人就卡在这里&#xff0c;怎么也不准&#xff0c;本人也是尝试过网上各种demo&#xff0c;基本上都是渣渣&#xff0c;要么仅仅支持极其少量的视频文件比如收到的数据包…

1119. Pre- and Post-order Traversals (30)

友情提示&#xff1a;这题非常值得自己思考独立做出来&#xff0c;请反复确认后再往下拉 1119. Pre- and Post-order Traversals (30) 时间限制400 ms内存限制65536 kB代码长度限制16000 B判题程序Special作者CHEN, YueSuppose that all the keys in a binary tree are distinc…

单招计算机英语面试口语,单招面试英语自我介绍范文 自我介绍说什么

单招面试英语自我介绍范文 自我介绍说什么2018-03-11 10:50:17文/李男学好英语就意味着可能有更多的机会&#xff0c;单招面试中英语自我介绍也是很重要的。那么&#xff0c;英语自我介绍说什么呢&#xff1f;下面小编整理了一些英语自我介绍范文&#xff0c;供大家参考&#x…

angularjs directive scope变化为啥html,学习AngularJs:Directive指令用法(完整版)

本教程使用AngularJs版本&#xff1a;1.5.3摘要&#xff1a;Directive(指令)笔者认为是AngularJ非常强大而有有用的功能之一。它就相当于为我们写了公共的自定义DOM元素或CLASS属性或ATTR属性&#xff0c;并且它不只是单单如此&#xff0c;你还可以在它的基础上来操作scope、绑…