Qt中使用QPdfWriter类结合QPainter类绘制并输出PDF文件

news/2025/2/21 7:14:17/

一.类的介绍

1.QPdfWriter介绍

Qt中提供了一个直接可以处理PDF的类,这就是QPdfWriter类。
(1)PDF文件生成
支持创建新的PDF文件或覆盖已有文件,通过构造函数直接绑定文件路径或QFile对象;
默认生成矢量图形PDF,支持高分辨率输出(可设置DPI);
2)页面属性配置
页面方向:通过setPageOrientation(QPageLayout::Orientation)设置纵向(Portrait)或横向(Landscape);
页面尺寸:使用setPageSize(QPageSize::A4)定义纸张大小,支持ISO标准尺寸(如A4、A3);
页边距:通过setPageMargins()调整内容区域与页边的距离;
(3)内容绘制
与QPainter深度集成,支持所有标准绘图操作:
图形:线段、矩形、椭圆、多边形等;
文本:多字体样式、对齐方式、旋转文字;
图像:支持PNG、JPG、SVG等格式的嵌入;
(4)多页面管理
通过QPainter::begin()和QPainter::end()控制绘制流程;
使用QPrinter::newPage()或手动分页逻辑实现多页文档;

2.QPainter介绍

(1)QPainter类功能
QPainter是Qt框架中用于2D图形绘制的核心类,提供高度优化的绘图功能,支持在QWidget、QImage、QPixmap、QPrinter等设备上进行绘制。其主要特性包括:

  • 支持矢量图形(直线/曲线/几何图形)和位图操作;
  • 提供坐标变换、复合模式、抗锯齿等高级特性;
  • 集成字体渲染、图像合成等专业级功能;
  • 必须通过paintEvent()事件或在继承自QPaintDevice的类中使用;
    (2)QPainter类接口
  1. 基础绘图操作
    在这里插入图片描述
  2. 文本与图像处理
    在这里插入图片描述
  3. 状态控制与高级特性
    在这里插入图片描述
    QPainter类还有很多接口函数,尤其是跟绘制有关的,很多重载的接口方便不同情况的使用,具体可以参考官网的介绍QPainter类。

二.开发生成PDF文件

下面开始用上文中的两个类来封装一个专门用来绘制PDF文件的类。

1.使用前要注意:

  • 坐标系系统:PDF坐标系原点在页面左上角,Y轴向下延伸,X轴向右延伸;
  • 单位换算:使用QPageLayout::Millimeter设置毫米单位,绘制时默认使用像素单位;
  • 图像缩放:推荐使用QRect参数控制图片显示尺寸,避免直接缩放;
  • 字体嵌入:中文字体需通过QFontDatabase加载系统字体;
  • 多页处理:通过QPdfWriter的newPage()创建新页面;

2.绘制流程梳理

  • 想要操作PDF文件,首先得有个文件,使用QFile的对象指向文件,然后创建QPdfWriter类的对象,并将QPdfWriter绑定在该文件上,然后用QPdfWriter对象设定PDF的一些参数,比如DPI,绘制页面大小等。
  • 其次,想要绘制得打开文件,调用QFile对象打开绑定的pdf格式的文件;
  • 再次,创建QPainter类对象,用该对象的各个规制接口来绘制各种图形文字等,如果你要设计绘制的接口很多的话,这里其实是最耗时的;
  • 最后,正确的释放资源,关闭文件;

3.代码说明

现在实操

  • QtCreator上创建一个简单的应用程序项目,先编译下,确保原始项目没问题;
  • 在程序界面上添加一个按钮,命名“btCreatePdf”,连接好按钮对应的点击信号槽;
  • 添加新的C++类,继承自QObject,类命名“PdfGenerator”,这就是我们准备开发的一个专门操作PDF的自定义类,也就是我们所有对PDF的操作都在这个类里边完成;
  • “PdfGenerator”类的设计开发,包含QPdfWriter,QPainter,QFont,QImage,QPageSize, QFile等类;创建QPdfWriter类的对象,QPainter类的对象,QFile类的对象;调用这些对象的接口实现PDF的绘制。
  • 最后,在主程序中包含上面自定义类,在界面按钮“btCreatePdf”中调用其实现PDF绘制。
    不多说,直接上代码:

PdfGenerator 类的头文件:


// pdfgenerator.h 
#include <QObject>
#include <QPdfWriter>
#include <QPainter>
#include <QFont>
#include <QImage>
#include <QPageSize>
#include <QFile>class PdfGenerator : public QObject {Q_OBJECT
public:explicit PdfGenerator(const QString &fileName, QPagedPaintDevice::PageSize size = QPagedPaintDevice::PageSize::A4);~PdfGenerator();// 基础设置 void setMargins(qreal left, qreal top, qreal right, qreal bottom);void setResolution(int dpi);void newPage();bool beginPage();bool endPage();// 绘制接口//绘制线段void drawLine(const QPointF &start, const QPointF &end, const QColor &color, qreal width);//绘制文字void drawText(const QRectF &rect, const QString &text, const QFont &font, const QColor &color, Qt::Alignment align);//绘制图片void drawImage(const QRectF &rect, const QString &imagePath, bool keepAspectRatio);//绘制矩形void drawRect(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth);//绘制椭圆void drawEllipse(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth);//想设计其他绘制接口继续往下加	private:QPdfWriter *m_writer = nullptr;QPainter *m_painter = nullptr;QRect m_pageRect;QFile m_pdfFile;
};

PdfGenerator 类的cpp文件

#include "PdfGenerator.h"
#include <QtDebug>
// pdfgenerator.cpp  
PdfGenerator::PdfGenerator(const QString &fileName, QPagedPaintDevice::PageSize size)
{m_pdfFile.setFileName(fileName);m_writer = new QPdfWriter(&m_pdfFile);m_writer->setPageSize(size);m_writer->setResolution(300);m_writer->setPageMargins(QMarginsF(20, 20, 20, 20), QPageLayout::Millimeter);m_pageRect = m_writer->pageLayout().paintRectPixels(m_writer->resolution());// 计算可绘制区域 m_pageRect = QRect(0, 0, m_writer->width(), m_writer->height());if(!m_pdfFile.open(QIODevice::WriteOnly))return ;}PdfGenerator::~PdfGenerator()
{if (m_painter->isActive()){m_painter->end();}delete m_painter;delete m_writer;
}void PdfGenerator::setMargins(qreal left, qreal top, qreal right, qreal bottom)
{m_writer->setPageMargins(QMarginsF(left, top, right, bottom), QPageLayout::Millimeter);m_pageRect = m_writer->pageLayout().paintRectPixels(m_writer->resolution()); // 更新绘制区域[5]()
}void PdfGenerator::newPage()
{// 创建新页m_writer->newPage();
}bool PdfGenerator::beginPage(){bool bRet = false;if(nullptr == m_painter){m_painter = new QPainter(m_writer);}//启用抗锯齿m_painter->setRenderHint(QPainter::Antialiasing);if (nullptr != m_painter){m_painter->begin(m_writer);//m_painter->reset(new  QPainter(m_writer.data()));bRet = m_painter->isActive();}qDebug() << "beginPage bRet is " << bRet;return bRet;
}bool PdfGenerator::endPage() {if (m_painter && m_painter->isActive()){m_painter->end();m_writer->deleteLater();m_pdfFile.close();return true;}m_pdfFile.close();return false;
}// 绘制线段 
void PdfGenerator::drawLine(const QPointF &start, const QPointF &end, const QColor &color, qreal width)
{if (!m_painter->isActive())return;m_painter->save();m_painter->setPen(QPen(color, width));m_painter->drawLine(start, end);m_painter->restore();
}// 绘制文本(支持对齐)
void PdfGenerator::drawText(const QRectF &rect, const QString &text, const QFont &font, const QColor &color, Qt::Alignment align)
{if (!m_painter->isActive()) return;m_painter->save();m_painter->setFont(font);m_painter->setPen(color);m_painter->drawText(rect, static_cast<int>(align), text);m_painter->restore();
}// 绘制图片(自动缩放)
void PdfGenerator::drawImage(const QRectF &rect, const QString &imagePath, bool keepAspectRatio)
{if (!m_painter->isActive())return;QPixmap pixmap(imagePath);if (pixmap.isNull())  return;QRectF targetRect = rect;if (keepAspectRatio) {QSizeF scaled = pixmap.size().scaled(rect.size().toSize(),  Qt::KeepAspectRatio);targetRect.setSize(scaled); }m_painter->drawPixmap(targetRect, pixmap, pixmap.rect()); 
}// 绘制矩形(支持填充)
void PdfGenerator::drawRect(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth)
{if (!m_painter->isActive())return;m_painter->save();m_painter->setBrush(QBrush(fillColor));m_painter->setPen(QPen(borderColor, borderWidth));m_painter->drawRect(rect);m_painter->restore();
}// 绘制椭圆 
void PdfGenerator::drawEllipse(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth)
{if (!m_painter->isActive()) return;m_painter->save();m_painter->setBrush(QBrush(fillColor));m_painter->setPen(QPen(borderColor, borderWidth));m_painter->drawEllipse(rect);m_painter->restore();
}

主程序按钮调用PdfGenerator类绘制PDF

//创建Pdf
void MainWindow::on_btCreatePdf_clicked()
{qDebug() << "into on_btCreatePdf_clicked";PdfGenerator doc("E:/test/output.pdf");if (doc.beginPage()){qDebug() << "beginPage success";// 绘制灰色线段doc.drawLine(QPointF(20,  60), QPointF(150, 200), Qt::lightGray, 2.0);// 添加图片(保持比例),例子的资源里没有添加这张图片,所以下面PDF里没有绘制出来图片doc.drawImage(QRectF(100,  100, 100, 100), "logo.png", false);// 绘制蓝色文字QFont font("Arial", 12, QFont::Bold);doc.drawText(QRectF(70,  270, 270, 50), "Hello PDF!", font, Qt::blue, Qt::AlignVCenter | Qt::AlignHCenter);// 绘制绿色填充矩形doc.drawRect(QRectF(300,  150, 100, 40), Qt::green, Qt::black, 1.5);// 绘制黄色边框椭圆doc.drawEllipse(QRectF(250,  200, 100, 80), Qt::transparent, Qt::yellow, 2.0);doc.endPage();}}

执行后,展示结果:
在这里插入图片描述
以此自定义PdfGenerator类作为基础,后续可以根据QPainter类本身带有的各种图形绘制功能,封装你想做的绘制接口,实际项目应用中,就以你封装的接口进行各种布局绘制操作,来完成项目要求。


http://www.ppmy.cn/news/1573820.html

相关文章

【DeepSeek 系列】DeepSeekMoE

文章目录 Transformers 中的 MoETransformer语言模型通用的MoE架构 DeepSeekMoE架构细粒度专家分割共享专家隔离负载均衡考虑 模型预训练不同尺寸模型超参数概览DeepSeekMoE 2B训练数据基础设施超参数 DeepSeekMoE 16B训练数据超参数 DeepSeekMoE 16B 的对齐训练数据超参数 总结…

Unity教程(二十一)技能系统 基础部分

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

【Linux】序列化、守护进程、应用层协议HTTP、Cookie和Session

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、序列化和反序列化2、守护进程2.1 什么是进程组&#xff1f;2.2 什么是会话&#xff1f; 3、应用层协议HTTP3.1 HTTP协议3.2 HT…

Mentalab Explore Pro:第三代移动 EEG 设备,开启便携式脑电研究新时代

Mentalab推出的Explore Pro是一款专为研究和工业领域设计的第三代移动脑电图&#xff08;EEG&#xff09;设备。它凭借很高的精度和小巧的尺寸&#xff0c;为脑电研究提供了新的可能性。这款设备凭借强大的功能和灵活的设计&#xff0c;成为研究人员在各种实验环境中重要的工具…

人工智能之视频分割模型sam2源码解读

目前只提供了测试的,没训练的代码这一块。 &#xff08;1&#xff09;下载源码后按下面几步操作&#xff1a; 也许vs版本低一点也行吧,至此视频已经切成图片了。 (2)预测 它是先把视频分割成图像,然后第一帧先指定要分割的那些东西,然后它就是每帧去处理,最后输出分割后的图像…

新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)

视频教程和更多福利在我主页简介或专栏里 &#xff08;不懂都可以来问我 专栏找我哦&#xff09; 如果对你有帮助你可以来专栏找我&#xff0c;我可以无偿分享给你对你更有帮助的一些经验和资料哦 目录&#xff1a; 一、XSS的三种类型&#xff1a; 二、XSS攻击的危害&#x…

基于 Flask 与 MySQL 构建简单的博客系统

引言 在互联网时代&#xff0c;博客是人们分享知识、记录生活的重要平台。借助 Python 的 Flask 框架与 MySQL 数据库&#xff0c;我们可以快速搭建一个简单的博客系统。本文将详细介绍如何从零开始构建这样一个系统&#xff0c;涵盖环境搭建、数据库设计、后端接口实现以及前端…

前端web安全

一、黑盒扫描和白盒扫描 白盒扫描和黑盒扫描都是针对网络安全和应用程序安全的常用测试方法。 1、白盒扫描指的是测试人员具有关于系统内部结构和代码的全部或部分信息&#xff0c;是基于源代码的安全检测方法&#xff0c;它可以对源代码进行深度分析&#xff0c;从而发现潜在…