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.rhkb.cn/news/490983.html

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

相关文章

【Leecode】Leecode刷题之路第82天之删除排序链表中的重复元素II

题目出处 82-删除排序链表中的重复元素 II-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 82-删除排序链表中的重复元素 II-官方解法 方法1&#xff1a;一次遍历 思路&#xff1a; 代码…

IDEA 可视化使用 git rebase 合并分支步骤 使git分支树保持整洁

模拟环境 dev 分支开发完一个功能&#xff0c;需要合并到 master 分支&#xff0c;如果现在直接 merge 合并的话 git分支树会出现杂乱分叉&#xff0c;先把 master 分支 rebase 到 dev git分支树就会是整洁的一条直线 git rebase介绍 rebase:翻译成中文是重新设定&#xff0c;…

短信验证码burp姿势

首先声明&#xff0c;本文仅仅作为学习使用&#xff0c;因个人原因导致的后果&#xff0c;皆有个人承担&#xff0c;本人没有任何责任。 在之前的burp学习中&#xff0c;我们学习了图片验证码的突破&#xff0c;但是现实中还有很多短信验证码&#xff0c;在此我介绍几种短信验…

你知道OSI参考模型是什么吗?

你知道OSI参考模型是什么吗&#xff1f; 一. OSI模型图解二. OSI七层模型三. OSI模型的特点四. OSI模型与TCP/IP模型的对比五. 总结 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱…

好用便签好用在哪里?

在这个信息如潮水般涌来&#xff0c;生活节奏快得像开了倍速的时代&#xff0c;我们的大脑常常被各种事务塞得满满当当&#xff0c;仿佛一台即将 “死机” 的电脑。这时候&#xff0c;我希望有一些工具能帮我轻松梳理这团乱麻&#xff0c;让一切变得井井有条。 从时间管理的维度…

Codeforces Round 993 (Div. 4)

Codeforces Round 993 (Div. 4) 2024.12.15 rank289 123&#xff1a;1381->1504 A Cube is given an integer n n n. She wants to know how many ordered pairs of positive integers ( a , b ) (a,b) (a,b) there are such that a n − b an-b an−b. Since Cube is…

Linux中的service命令

service命令 在Linux系统中&#xff0c;service命令是用来启动、停止、重启以及查看系统服务状态的一个常用命令。服务&#xff0c;或称为守护进程&#xff0c;是在后台运行的进程&#xff0c;它们通常会监听某个端口&#xff0c;等待其他程序的请求。例如&#xff0c;MySQL、…

R环境配置 以及Debug方法 (VSCode, conda, 远程R)

生物信息学中的R环境配置 以及Debug方法 开始设置1、建议使用VSCode conda 远程R2、 VSCode配置安装插件安装好插件后&#xff0c;远程设置链接成功后&#xff0c;设置项目 3、 linux conda 和 远程R配置4、VScode 远程访问R环境下面配置远程R 5、开始Debug新建个R文件&#…

druid图形化监控 + MyBatis优化器使用

文章目录 1.集成druid图形化监控1.配置application.yml2.测试访问 http://localhost:项目端口/druid 2.MyBatis优化器(显示完整sql)1.目录2.SqlBeautyInterceptor.java&#xff1a;sql拦截器3.MybatisConfiguration.java&#xff1a;将sql拦截器注入容器4.测试5.MyBatis优化器动…

【经验分享】私有云运维的知识点

最近忙于备考没关注&#xff0c;有次点进某小黄鱼发现首页出现了我的笔记还被人收费了 虽然我也卖了一些资源&#xff0c;但我以交流、交换为主&#xff0c;笔记都是免费给别人看的 由于当时刚刚接触写的并不成熟&#xff0c;为了避免更多人花没必要的钱&#xff0c;所以决定公…

Unity 2020、2021、2022、2023、6000下载安装

Unity 2020、2021、2022、2023、6000 下载安装 以Unity 6000.0.24fc1下载安装为例&#xff1a; 打开 https://unity.cn/ 优三缔 官方网站&#xff1b; 点击【产品列表】→点击【查看更多】→选择自己需要的版本→点【开始使用】 点击【从Unity Hub下载】 以Windows为例&am…

240004】基于maven的java+ssm+mysql的房屋租赁系统的设计与实现

基于ssmmavenmysql的房屋租赁系统的设计与实现 1.项目描述2.运行环境3.项目截图4.源码获取 1.项目描述 该项目在原有的基础上进行了优化&#xff0c;包括新增了注册功能&#xff0c;房屋模糊查询功能&#xff0c;管理员和用户信息管理等功能&#xff0c;以及对网站界面进行了优…

NEEP-EN2-2023-Section5PartB

题目 个人答案 The chart depicts the outcomes of a survey conducted in a specific university regarding the acquisition of practical activity in class. The chart illustrates that learning knowledges accounts for 91.3 percent, which is the highest percentage…

WPF 控件

<div id"content_views" class"htmledit_views"><p id"main-toc"><strong>目录</strong></p> WPF基础控件 按钮控件&#xff1a; Button:按钮 RepeatButton:长按按钮 RadioButton:单选按钮 数据显示控件 Te…

系列1:基于Centos-8.6部署Kubernetes (1.24-1.30)

每日禅语 “木末芙蓉花&#xff0c;山中发红萼&#xff0c;涧户寂无人&#xff0c;纷纷开自落。​”这是王维的一首诗&#xff0c;名叫《辛夷坞》​。这首诗写的是在辛夷坞这个幽深的山谷里&#xff0c;辛夷花自开自落&#xff0c;平淡得很&#xff0c;既没有生的喜悦&#xff…

ESP8266 Ubuntu 安装

文章参考&#xff1a;https://blog.csdn.net/AUST_129/article/details/119406722文章浏览阅读1.8k次&#xff0c;点赞4次&#xff0c;收藏19次。参考&#xff1a;https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/get-started/linux-setup.htmlhttp://aicloud…

软件压力测试和负载测试有什么联系与区别?

在当今数字化时代&#xff0c;软件质量的重要性愈发凸显。在各种软件测试中&#xff0c;压力测试和负载测试都属于性能测试中的一种测试方法&#xff0c;那么这两者分别是什么?又有什么联系和区别呢? 一、压力测试和负载测试的定义   压力测试通常是指在特定的环境中&…

C# 异常处理 详解

总目录 前言 一、异常 1、定义 异常是在程序执行期间出现的问题。 C# 中的异常是对程序运行时出现的特殊情况的一种响应&#xff0c;比如尝试除以零。 异常&#xff1a;程序员必须控制和解决的问题。程序可以正常的运行&#xff0c;但是在运行的过程中出现了问题&#xff0c;…

类OCSP靶场-Kioptrix系列-Kioptrix Level 2

一、前情提要 二、实战打靶 1. 信息收集 1.1. 主机发现 1.2. 端口扫描 1.3.目录遍历 2.漏洞发现 2.1. 登录框测试 2.2. 发现命令执行 2.3 构造命令执行利用payload 3.提权 3.1. 搜索提权exp 3.2. 查看exp信息 3.3. Privilege Escalation的exp利用 exp_9542 一、前…

μC/OS-Ⅱ源码学习(6)---事件标志组

快速回顾 μC/OS-Ⅱ中的多任务 μC/OS-Ⅱ源码学习(1)---多任务系统的实现 μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下) μC/OS-Ⅱ源码学习(3)---事件模型 μC/OS-Ⅱ源码学习(4)---信号量 μC/OS-Ⅱ源码学习(5)---消息队列 本文进一步解析事件模型中&#xff0c;事件标志…