Qt WORD/PDF(二)使用 QtPdfium库实现 PDF操作、打印等


关于QT Widget 其它文章请点击这里:     QT Widget

GitHub 源码:     QWidgetLearningPro (暂未更新)

姊妹篇:      Qt WORD/PDF(一)使用 QtPdfium库实现 PDF 预览


一、简介

QtPdfium 是基于Pdfium库的一个Qt绑定。Pdfium是一个由Google开发并开源的PDF渲染引擎,它被广泛应用于Chrome浏览器和其他一些Google产品中。QtPdfium则是一个专门将Pdfium引入Qt项目的封装,使得Qt应用程序可以使用Pdfium的PDF渲染功能。

它的主要目标是高效的PDF文档渲染,特别是在Web浏览器等高性能需求的应用场景中。相较于Poppler,Pdfium侧重于简洁、高效的渲染和性能优化。

二、演示

在这里插入图片描述

三、代码部分

完整代码

mainwindow.cpp:

#include "mainwindow.h"// #include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QFileDialog>
#include <QPrinter>
#include <QPrintDialog>
#include <QPainter>
#include <QPrinterInfo>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)// , ui(new Ui::MainWindow)
{// 设置窗口标题setWindowTitle("PDF Viewer & Printer");this->initWidget();// 主控件和布局QWidget *centralWidget = new QWidget(this);QVBoxLayout *layout = new QVBoxLayout(centralWidget);// PDF 预览区域m_pdfPreview = new QLabel("PDF 预览区域", this);m_pdfPreview->setFixedSize(700, 880);m_pdfPreview->setStyleSheet("border: 1px solid gray; background-color: #f0f0f0;");m_pdfPreview->setAlignment(Qt::AlignCenter);layout->addWidget(m_pdfPreview);//增加一行页码相关,页码控制区域//上一页 当前页/总页码 下一页QHBoxLayout *pageControlLayout = new QHBoxLayout();_prevPageButton = new QPushButton("上一页", this);_pageInfoLabel = new QLabel("0 / 0", this);_nextPageButton = new QPushButton("下一页", this);_pageInfoLabel->setAlignment(Qt::AlignCenter);// 将控件添加到水平布局中pageControlLayout->addWidget(_prevPageButton);pageControlLayout->addWidget(_pageInfoLabel);pageControlLayout->addWidget(_nextPageButton);layout->addLayout(pageControlLayout);// 打印设置区域QHBoxLayout *printerLayout = new QHBoxLayout();m_printerList = new QComboBox(this);m_currentPage = new QRadioButton("当前页", this);m_allPages = new QRadioButton("所有页", this);m_allPages->setChecked(true); // 默认打印所有页m_rangeGroup = new QButtonGroup(this);m_rangeGroup->addButton(m_currentPage);m_rangeGroup->addButton(m_allPages);printerLayout->addWidget(new QLabel("打印机:", this));printerLayout->addWidget(m_printerList);printerLayout->addWidget(m_currentPage);printerLayout->addWidget(m_allPages);layout->addLayout(printerLayout);// 按钮区域QHBoxLayout *buttonLayout = new QHBoxLayout();m_loadButton = new QPushButton("加载PDF", this);m_printButton = new QPushButton("打印PDF", this);buttonLayout->addWidget(m_loadButton);buttonLayout->addWidget(m_printButton);layout->addLayout(buttonLayout);setCentralWidget(centralWidget);// 填充打印机列表populatePrinters();// 信号与槽连接connect(_prevPageButton, &QPushButton::clicked, this, &MainWindow::goToPreviousPage);connect(_nextPageButton, &QPushButton::clicked, this, &MainWindow::goToNextPage);connect(m_loadButton, &QPushButton::clicked, this, &MainWindow::loadPdf);connect(m_printButton, &QPushButton::clicked, this, &MainWindow::printPdf);}MainWindow::~MainWindow()
{m_pdfium = nullptr;delete m_pdfium;
}//初始化界面
void MainWindow::initWidget()
{//初始化变量_currentPage = 0;               // 当前页码_totalPages = 0;                // 总页数
}void MainWindow::populatePrinters()
{// 获取系统打印机列表QList<QPrinterInfo> printers = QPrinterInfo::availablePrinters();for (const QPrinterInfo &printer : printers) {m_printerList->addItem(printer.printerName());}
}//鼠标滚轮事件,放大缩小
void MainWindow::wheelEvent(QWheelEvent *event)
{if(!isPdfValid) {return;}//根据鼠标滚轮的方向来缩放图像const QPoint numDegrees = event->angleDelta() / 8;const int numSteps = numDegrees.y() / 15;if(numSteps != 0){//更新缩放比例if(numSteps > 0) {//放大zoomScale *= 1.1;}else {//缩小,但要确保缩放比例不会小于某个最小值(比如0.1)zoomScale /= 1.1;zoomScale = qMax(zoomScale, 0.3);}//更新缩放后的图像并显示updateScaledPixmap();}
}//更新缩放图像
void MainWindow::updateScaledPixmap()
{//计算缩放后的尺寸QSize scaledSize = _showPixmap.size() * zoomScale;//缩放图像QPixmap scaledPixmap = _showPixmap.scaled(scaledSize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);//更新QLabel的Pixmapm_pdfPreview->setPixmap(scaledPixmap);
}void MainWindow::loadPdf()
{// 打开文件对话框加载 PDFQString fileName = QFileDialog::getOpenFileName(this, "选择PDF文件", "D:/23_Outproject/32_ZNPicture/Src/QtPdfiumTest2", "PDF Files (*.pdf)");if (fileName.isEmpty()) {isPdfValid = false;return;}m_pdfium = new QPdfium();// 加载 PDF 文件m_pdfium->loadFile(fileName);isPdfValid = m_pdfium->isValid();if (!isPdfValid) {m_pdfPreview->setText("加载PDF失败!");return;}_totalPages = m_pdfium->pageCount(); // 更新总页数_currentPage = 0;                    // 当前页重置为第一页_pageInfoLabel->setText(QString("%1 / %2").arg(_currentPage+1).arg(_totalPages));//预览第一页QPdfiumPage page = m_pdfium->page(_currentPage);if (page.isValid()) {QImage image = page.image(1.0); // 渲染为 QImage_showPixmap = QPixmap::fromImage(image).scaled (m_pdfPreview->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);m_pdfPreview->setPixmap(_showPixmap);}
}//上一页
void MainWindow::goToPreviousPage()
{if (_currentPage > 0) {_currentPage--;_pageInfoLabel->setText(QString("%1 / %2").arg(_currentPage+1).arg(_totalPages));QPdfiumPage page = m_pdfium->page(_currentPage);if (page.isValid()) {QImage image = page.image(1.0);_showPixmap = QPixmap::fromImage(image).scaled (m_pdfPreview->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);m_pdfPreview->setPixmap(_showPixmap);}}
}//下一页
void MainWindow::goToNextPage()
{if (_currentPage < _totalPages-1) {_currentPage++;_pageInfoLabel->setText(QString("%1 / %2").arg(_currentPage+1).arg(_totalPages));QPdfiumPage page = m_pdfium->page(_currentPage);if (page.isValid()) {QImage image = page.image(1.0);_showPixmap = QPixmap::fromImage(image).scaled (m_pdfPreview->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);m_pdfPreview->setPixmap(_showPixmap);}}
}void MainWindow::printPdf()
{// 调用打印功能if (!m_pdfium || !m_pdfium->isValid() || m_pdfium->pageCount() == 0) {m_pdfPreview->setText("未加载有效PDF,无法打印!");return;}// 创建打印机对象QPrinter printer(QPrinter::HighResolution);printer.setPrinterName(m_printerList->currentText());//是用来设置打印页面的方向,指定打印内容的布局是 纵向 (Portrait) 还是 横向 (Landscape)。printer.setOrientation(QPrinter::Portrait);printer.setPageSize(QPrinter::A4);// 设置打印范围int fromPage = 1;int toPage = m_pdfium->pageCount();if (m_currentPage->isChecked()) {fromPage = toPage = 1; // 当前页为第一页}// 打印 PDFQPainter painter(&printer);for (int i = fromPage; i <= toPage; ++i) {QPdfiumPage page = m_pdfium->page(i);if (!page.isValid()) continue;QImage image = page.image(1.0);QRect targetRect = printer.pageRect();QPixmap pixmap = QPixmap::fromImage(image).scaled (targetRect.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);painter.drawPixmap(0, 0, pixmap);if (i < toPage)printer.newPage();}painter.end();
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>#include <QFileDialog>
#include <QDesktopServices>
#include <QTime>
#include <QImage>
#include <QPixmap>
#include <QWheelEvent>
#include <QDebug>#include "qpdfium.h"#include <QPrinter>
#include <QPainter>
#include <QPrintDialog>
#include <QFileDialog>//Item
#include <QWheelEvent>
#include <QLabel>
#include <QPushButton>
#include <QComboBox>
#include <QRadioButton>
#include <QPrinter>
#include <QButtonGroup>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void initWidget();  //         初始化参数void showPdfData(int curPage);void updateScaledPixmap();protected:void wheelEvent(QWheelEvent *event) override;private slots:void goToPreviousPage();       // 上一页槽函数void goToNextPage();           // 下一页槽函数void loadPdf();void printPdf();private:Ui::MainWindow *ui;int m_curPage;                  //当前页int m_totalPage;                //总页数double  zoomScale;              //缩放比例bool    isPdfValid = false;     //打开pdf是否有效QString m_saveImagePath;        //图像保存路径QPixmap _showPixmap;           //界面显示图像//Item1QPushButton *_prevPageButton; // 上一页按钮QPushButton *_nextPageButton; // 下一页按钮QLabel      *_pageInfoLabel;  // 当前页/总页码显示//Item2QPdfium *m_pdfium = nullptr;    //QPdfium对象QLabel *m_pdfPreview;           // 用于显示PDF预览QPushButton *m_loadButton;      // 加载PDF按钮QPushButton *m_printButton;     // 打印按钮//基本参数int _currentPage;               // 当前页码int _totalPages;                // 总页数QComboBox *m_printerList;       // 打印设备列表QRadioButton *m_currentPage;    // 打印范围:当前页QRadioButton *m_allPages;       // 打印范围:所有页QButtonGroup *m_rangeGroup;     // 打印范围按钮组void populatePrinters();        // 获取系统打印机
};
#endif // MAINWINDOW_H

pro 中需要增加对打印的支持

QT       += core gui printsupport

简要分析

1. 初始化界面 (MainWindow::MainWindow)

  • 创建并配置了主界面控件,包括 PDF 预览区域、页码控制、打印设置、按钮区域。
  • 使用 QVBoxLayoutQHBoxLayout 布局管理器来组织控件。
  • QLabel 用于显示 PDF 预览,QPushButton 控件用于加载 PDF 文件和打印 PDF。
  • QComboBoxQRadioButton 用于选择打印机和打印范围(当前页或所有页)。
  • 设置了信号与槽连接:控制按钮的点击事件(加载 PDF、打印 PDF、翻页等)。

2. 控件的布局和显示

  • PDF 预览区域使用 QLabel 来显示 PDF 页面图像,用户可以通过上下页按钮查看不同页。
  • 页码信息通过 QLabel 显示(例如 “1 / 10” 表示当前第 1 页,总共有 10 页)。
  • 打印区域提供了选择打印机和打印选项(当前页或所有页)。
  • 通过 QPushButton 控件加载和打印 PDF 文件。

3. 加载 PDF 文件 (MainWindow::loadPdf)

  • 使用 QFileDialog::getOpenFileName 打开文件对话框,让用户选择 PDF 文件。
  • 通过 QPdfium 类(可能是一个自定义类)加载 PDF 文件。若加载成功,更新总页数并显示第一页。
  • QPdfiumPage 用于获取指定页的图像,将其转换为 QPixmap 后显示在 QLabel 中。

4. 翻页功能

  • goToPreviousPagegoToNextPage 用于上一页和下一页功能,页面切换时更新页码并渲染该页图像。

5. 打印功能 (MainWindow::printPdf)

  • 使用 QPrinter 设置打印机、页面大小、打印方向等。
  • QPainter 用于将 PDF 页面的图像绘制到打印机上。
  • 如果选择打印当前页,则仅打印当前页;如果选择打印所有页,则打印整个 PDF 文件的所有页面。
  • 在每一页打印完后,调用 printer.newPage() 使打印机跳转到下一页。

6. 鼠标滚轮放大缩小

  • wheelEvent 捕获鼠标滚轮事件,根据滚动方向来缩放 PDF 页面的显示。缩放比例由 zoomScale 控制,放大时乘以 1.1,缩小时除以 1.1。 调整后更新显示;

7. 打印机列表填充

  • populatePrinters 方法列出系统中的打印机,将其添加到 QComboBox 控件中

注意:

  1. 使用 QtPdfium 偶尔无法读中文路径的PDF,不知道是不是库本身的问题;
  2. PDF 渲染效率:每次翻页时都重新加载页面并进行图像渲染,若 PDF 页数较多或者页面较复杂时可能会影响性能。可以考虑缓存已经渲染过的页面,减少重复渲染

参考:

Qt下使用QtPdfium处理PDF文档


商务合作请加我: 19976699725

关于QT Widget 其它文章请点击这里:     QT Widget

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

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

相关文章

信息收集(dns信息收集dnsenum和路由收集traceroute)

导入 被动收集方式不容易被目标域发现 DNS信息收集 网络拓扑结构以及网络设置 服务机 路由器 kali机 查看并设置默认网关 工具 或者在系统目录下可找到dns的工具 dnsenum dnsenum -h 帮助指令 收集百度域的指令 使用字典文件破解对查找目标域进行收集 dnsmap 对自己的虚拟机…

Java设计模式 —— 【结构型模式】适配器模式(类的适配器、对象适配器、接口适配器)详解

文章目录 基本介绍一、类的适配器二、对象适配器三、接口适配器总结 基本介绍 生活中有很多例子&#xff1a; 不同国家的插座接口不同&#xff0c;需要转换器&#xff1b;家用电源220V&#xff0c;手机只接受5V充电&#xff0c;需要转换器&#xff1b;读卡器&#xff0c;拓展…

启明智显ZX7981PC:5G时代的新选择,全屋网络无缝覆盖

在这个飞速发展的5G时代&#xff0c;每一个细微的科技进步都在推动着我们的生活向更加智能、便捷的方向发展。近日&#xff0c;启明智显再次引领科技潮流&#xff0c;正式发布其最新的5G CPE产品——ZX7981PC。作为继7981PG与7981PM之后的又一次迭代升级&#xff0c;ZX7981PC凭…

11篇--图像边缘检测

图像梯度 要学习图像边缘检测&#xff0c;要先了解图像梯度的概念&#xff0c;我们正是通过梯度值来区分边缘像素点的 处于边缘附近的像素点与周围像素点的差距很大&#xff08;不然不会有边缘呈现&#xff09;&#xff0c;所以给边缘附近的的梯度之变化很快&#xff0c;通过…

6.2 MapReduce工作原理

MapReduce工作原理涉及将大数据集分割成小块并行处理。Map任务读取数据块并输出中间键值对&#xff0c;而Reduce任务则处理这些排序后的数据以生成最终结果。MapTask工作包括读取数据、应用Map函数、收集输出、内存溢出时写入磁盘以及可选的Combiner局部聚合。ReduceTask工作则…

ARM Cortex-A7 MPCore 架构

1、Cortex-A7 MPCore 简介 Cortex-A7 MPcore 处理器支持 1~4 核&#xff0c;通常是和 Cortex-A15 组成 big.LITTLE 架构的&#xff0c; Cortex-A15 作为大核负责高性能运算&#xff0c;比如玩游戏啥的&#xff0c; Cortex-A7 负责普通应用&#xff0c;因为 CortexA7 省电。 Co…

天天 AI-241215:今日热点-OpenAI发布ChatGPT Projects,万能工具箱上线!

2AGI.NET | 探索 AI 无限潜力&#xff0c;2AGI 为您带来最前沿资讯。 2024年&#xff0c;人工智能&#xff08;AI&#xff09;领域的发展日新月异&#xff0c;不断刷新我们对技术边界的认知。从预训练模型的终结宣言到AI应用开发平台的受欢迎程度&#xff0c;再到AI在数据管理和…

CEF127 编译指南 MacOS 篇 - 安装 Git 和 Python(三)

1. 引言 在前面的文章中&#xff0c;我们已经完成了 Xcode 及基础开发工具的安装和配置。接下来&#xff0c;我们需要安装两个同样重要的工具&#xff1a;Git 和 Python。这两个工具在 CEF 的编译过程中扮演着关键角色。Git 负责管理和获取源代码&#xff0c;而 Python 则用于…

手机静态ip地址怎么获取?方法全解析‌

在数字化时代&#xff0c;智能手机已成为我们日常生活中不可或缺的一部分。无论是工作、学习还是娱乐&#xff0c;手机都扮演着至关重要的角色。而在某些特定情境下&#xff0c;我们可能需要为手机设置一个静态IP地址。本文将详细介绍如何为手机获取静态IP地址。 一、通过手机设…

FlightAD 解读

一 文章相关信息 出处&#xff1a;ICPADS CCF C 会议&#xff08;代码未开源&#xff09;&#xff0c;COUTA 研究团队的另一研究 二 Methodology 1. 整体架构&#xff1a; 2. Multi-Scale Sampling&#xff08;多尺度&#xff09; 实际上&#xff0c;就是对每个单通道作 “多…

【考前预习】4.计算机网络—网络层

往期推荐 【考前预习】3.计算机网络—数据链路层-CSDN博客 【考前预习】2.计算机网络—物理层-CSDN博客 【考前预习】1.计算机网络概述-CSDN博客 目录 1.网络层概述 2.网络层提供的两种服务 3.分类编址的IPV4 4.无分类编址的IPV4—CIDR 5.IPV4地址应用规划 5.1使用定长子…

github配置pages并配置自定义域名

有cloudflare的话实现的效果更好&#xff0c;可以使用自己的域名&#xff0c;实现白嫖一个网站服务器 1、配置git&#xff08;可选步骤&#xff09; git init git config --global user.name "sijia" git config --global user.email "devopsgame.vip"g…

vue3 结合 echarts 为tooltip绑定点击事件实现树形结构下动态添加子节点的效果

先看效果 具体实现代码如下&#xff1a; <template> <div ref"ecs" id"ecs" style"width: 800px;height:800px; background-color:white;"></div> </template><script setup> import {onMounted, ref} from &quo…

【JavaWeb后端学习笔记】Redis常用命令以及Java客户端操作Redis

redis 1、redis安装与启动服务2、redis数据类型3、redis常用命令3.1 字符串String3.2 哈希Hash3.3 列表List3.4 集合Set&#xff08;无序&#xff09;3.5 有序集合zset3.6 通用命令 4、使用Java操作Redis4.1 环境准备4.2 Java操作字符串String4.3 Java操作哈希Hash4.4 Java操作…

js:我要在template中v-for循环遍历这个centrerTopdata,我希望自循环前面三个就可以了怎么写

问&#xff1a; 我按在要在template中v-for循环遍历这个centrerTopdata&#xff0c;我希望自循环前面三个就可以了怎么写&#xff1f; 回答&#xff1a; 问&#xff1a; <div v-for"(item, index) in centrerTopdata.slice(0, 3)" :key"index"> d…

前端成长之路:CSS(1)

在前端三件套中&#xff0c;CSS的主要是用于美化网页、进行页面布局的。 HTML的局限性 HTML是一个非常单纯的语言&#xff0c;它只关心内容的语义&#xff1a; 比如看见h1标签&#xff0c;就表明这是一个大标题、看见p标签&#xff0c;就表明这是一个段落、看见img标签&#…

微服务SpringCloud链路追踪之Micrometer+Zipkin

视频教程&#xff1a; https://www.bilibili.com/video/BV12LBFYjEvR 效果演示 当我们发送一个请求给 Gateway 的时候&#xff0c;由 Micrometer trace 进行链路追踪和数据收集&#xff0c;由 Zipkin 进行数据展示。可以清楚的看到微服务的调用过程&#xff0c;以及每个微服务…

0001.基于springmvc简易酒店管理系统后台

一.系统架构 springmvcjsplayuimysql 二.功能特性 简单易学习&#xff0c;虽然版本比较老但是部署方便&#xff0c;tomcat环境即可启用&#xff1b;代码简洁&#xff0c;前后端代码提供可统一学习&#xff1b;祝愿您能成尽快为一位合格的程序员&#xff0c;愿世界没有BUG; …

Elasticsearch Kibana (windows版本) 安装和启动

目录 1.安装 2.启动 elasticsearch 3.启动 kibana 1.安装 elasticsearch下载&#xff0c;官网链接&#xff1a; Download Elasticsearch | Elastichttps://www.elastic.co/downloads/elasticsearch kibana下载&#xff0c;官网链接&#xff1a; Download Kibana Free | G…

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料预测效果 基本介绍 CNN-BiGRU,即卷积神经网络(CNN)与双…