QT 使用QPdfWriter和QPainter绘制PDF文件
QT如何生产pdf文件,网上有许多文章介绍,我也是看了网上的文章,看他们的代码,自己琢磨琢磨,才有了本编博客;
其他什么就不详细说了,本篇博客介绍的QPdfWriter和QPainter绘制PDF文件;对pdf这里是绘制出来的,没有什么规范的格式,都是通过xy坐标绘制出来的。
QPdfWriter类设置pdf的基础设置;QPainter类绘制文本,图片矩形等;
以下代码参考博客:Qt中使用QPdfWriter类结合QPainter类绘制并输出PDF文件-CSDN博客
自己稍微做了调整了修改!
反正得自己会QPainter绘制,否则你无法绘制pdf文件出来!!!
头文件:
#include <QPdfWriter>
#include <QDesktopServices>
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QtPrintSupport>
一、步骤
绘制pdf有以下步骤:
1.选择需要导出的pdf文件路径;
2.创建pdf文件;
3.创建生成pdf类,作为绘图设备;
4.绘制PDF;
5.查看绘制好的pdf。
void Widget::exportPdf()
{//一、选择保存pdf文件路径QString sPath = QFileDialog::getSaveFileName(this, tr("另存为"), "/", tr("Text Files (*.pdf)"));if(sPath.isEmpty()){return;}qDebug() << sPath;//二、创建pdf文件QFile pdfFile(sPath);pdfFile.open(QIODevice::WriteOnly);//三、创建生成pdf类,作为绘图设备QPdfWriter *pPdfWriter = new QPdfWriter(&pdfFile);pPdfWriter->setResolution(300); // 将打印设备的分辨率设置为屏幕分辨率pPdfWriter->setPageSize(QPagedPaintDevice::A4); // 设置纸张为A4纸pPdfWriter->setPageMargins(QMarginsF(30, 30, 30, 30)); // 设置页边距 顺序是:左上右下//四、开始绘制PDF//paintPdf(pPdfWriter);delete pPdfWriter;pdfFile.close();//通过其它PDF阅读器来打开刚刚绘制的PDFQDesktopServices::openUrl(QUrl::fromLocalFile(sPath));
}
二、效果展示
三、代码实现
#include "widget.h"
#include "ui_widget.h"#include <QFileDialog>
#include <QStandardPaths>
#include <QPdfWriter>
#include <QDebug>
#include <QDesktopServices>
#include <QMessageBox>
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QtPrintSupport>#include <pdfgenerator.h>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);createPDF();
}Widget::~Widget()
{delete ui;
}void Widget::createPDF()
{int y = 0;QString path = "/home/UOS/Desktop/3.pdf";PdfGenerator *pdfGenerator = new PdfGenerator;bool flag = pdfGenerator->setFileName(path);if (!flag) {return ;}int nPdfWidth = pdfGenerator->getPdfWidth();pdfGenerator->beginPage();QPixmap p;p.load(":/007.jpg");int pHeight = pdfGenerator->drawImage(QRectF(0, y, 150, 150), p);y += pHeight + 50;// 绘制表格y += 100;QFont f = QFont("宋体", 18, 36);QColor blackColor = QColor(0,0,0);pdfGenerator->drawRect(QRectF(0, y, nPdfWidth, 200), blackColor, 2, QColor(100, 0, 200, 50));pdfGenerator->drawText(QRectF(0, y, nPdfWidth, 200), "这是标题文本!", QFont("宋体", 32, 64));// 绘制科目y += 200;int nClassWidthFlag = nPdfWidth / (8);int nClassWidth = nClassWidthFlag;QList<QString> classList;classList << "语文" << "数学" << "英语" << "历史" << "政治" << "地理" << "音乐" << "体育";int classx = 0;for (int i = 0; i < classList.count(); i++) {pdfGenerator->drawRect(QRectF(classx, y, nClassWidth, 100), blackColor, 2);pdfGenerator->drawText(QRectF(classx, y, nClassWidth, 100), classList.at(i), QFont("宋体", 12, 20), QColor(200, 100, 100), Qt::AlignCenter);classx += nClassWidth;if (7 == i + 1) {int n = nPdfWidth - (classx + nClassWidth);nClassWidth += n;}}// 绘制个人信息y += 100;int nPersonDescriptionWidth = nClassWidthFlag * 2;QList<QList<QString>> descriptionList;QList<QString> list;list << "小米" << "男" << "15";descriptionList << list;list.clear();list << "小明" << "男" << "20";descriptionList << list;list.clear();list << "小红" << "女" << "21";descriptionList << list;list.clear();list << "姓名" << "性别" << "年龄";int nPersonDescriptionHeight = 120 + descriptionList.count() * 100;pdfGenerator->drawRect(QRect(0, y, nPersonDescriptionWidth, nPersonDescriptionHeight));pdfGenerator->drawText(QRect(0, y, nPersonDescriptionWidth, nPersonDescriptionHeight), "个人信息",QFont("宋体", 20, 40), QColor(100, 100, 255));int nMessageX = nPersonDescriptionWidth;int nMessageWidth = nPersonDescriptionWidth;for (int i = 0; i < list.count(); i++) {pdfGenerator->drawRect(QRect(nMessageX, y, nMessageWidth, 120));pdfGenerator->drawText(QRect(nMessageX, y, nMessageWidth, 120), list.at(i), QFont("宋体", 18, 30), QColor(200, 50, 50));nMessageX += nPersonDescriptionWidth;if (list.count()-1 == i + 1) {int n = nPdfWidth - (nMessageX + nPersonDescriptionWidth);nMessageWidth += n;}}y += 120;int nPersonX = nPersonDescriptionWidth;int nPersonWidth = nPersonDescriptionWidth;for (int i = 0; i < descriptionList.count(); ++i) {QList<QString> list = descriptionList.at(i);for (int j = 0; j < list.count(); ++j) {pdfGenerator->drawRect(QRect(nPersonX, y, nPersonWidth, 100));pdfGenerator->drawText(QRect(nPersonX, y, nPersonWidth, 100), list.at(j), pdfGenerator->getBaseFont());nPersonX += nPersonDescriptionWidth;if (list.count()-1 == j + 1) {int n = nPdfWidth - (nPersonX + nPersonDescriptionWidth);nPersonWidth += n;}}y += 100;nPersonX = nPersonDescriptionWidth;nPersonWidth = nPersonDescriptionWidth;}// 绘制详细信息descriptionList.clear();list.clear();list << "小明" << "swim" << "擅长蛙泳" << "170cm";descriptionList << list;list.clear();list << "小红" << "dance" << "街舞鼻祖" << "160cm";descriptionList << list;list.clear();list << "小黄" << "run" << "短跑小王子" << "166cm";descriptionList << list;list.clear();list << "小绿" << "jump" << "跳高运动员" << "196cm";descriptionList << list;list.clear();list << "姓名" << "爱好" << "特点" << "身高";int nDetailedInformationWidth = nClassWidthFlag * 2;int nDetailedInformationHeight = 120 + descriptionList.count() * 100;pdfGenerator->drawRect(QRect(0, y, nDetailedInformationWidth, nDetailedInformationHeight));pdfGenerator->drawText(QRect(0, y, nDetailedInformationWidth, nDetailedInformationHeight), "详细信息",QFont("宋体", 20, 40), QColor(100, 100, 255));int nInformationTotalWidth = nPdfWidth - nDetailedInformationWidth;int nInformationOneWidth = nInformationTotalWidth / descriptionList.count();int nDetailedX = nDetailedInformationWidth;int nDetailedWidth = nInformationOneWidth;for (int i = 0; i < list.count(); i++) {pdfGenerator->drawRect(QRect(nDetailedX, y, nDetailedWidth, 120));pdfGenerator->drawText(QRect(nDetailedX, y, nDetailedWidth, 120), list.at(i), QFont("宋体", 20, 30));nDetailedX += nDetailedWidth;if (list.count()-1 == i + 1) {int n = nPdfWidth - (nDetailedX + nDetailedWidth);nDetailedWidth += n;}}y += 120;int nInformationX = nDetailedInformationWidth;int nInformationWidth = nInformationOneWidth;for (int i = 0; i < descriptionList.count(); ++i) {QList<QString> list = descriptionList.at(i);for (int j = 0; j < list.count(); ++j) {pdfGenerator->drawRect(QRect(nInformationX, y, nInformationWidth, 100));pdfGenerator->drawText(QRect(nInformationX, y, nInformationWidth, 100), list.at(j),pdfGenerator->getBaseFont(), QColor(200,0,0));nInformationX += nInformationWidth;if (list.count()-1 == j + 1) {int n = nPdfWidth - (nInformationX + nInformationWidth);nInformationWidth += n;}}y += 100;nInformationX = nDetailedInformationWidth;nInformationWidth = nInformationOneWidth;}y += 50;pdfGenerator->drawPolygon(QRect(600, y, 800, 600));pdfGenerator->drawRect(QRect(600, y, 800, 600));// 换页// if(y + 100 >= pdfGenerator->getPdfHeight()) {// pdfGenerator->newPage();// y = 10;// }pdfGenerator->newPage();y = 0;/************************************************************************************************************/// 外部大矩形框pdfGenerator->drawRect(QRect(0, y, nPdfWidth, pdfGenerator->getPdfHeight()), QColor(0,0,0), 8);// 左上角m级f = pdfGenerator->getBaseFont();f.setBold(true);f.setPointSize(13);pdfGenerator->drawText(QRectF(10, y, 360, 100), "m级:非m", f, QColor(0,0,0), Qt::AlignLeft);// 页码int pageX = 900;f = pdfGenerator->getBaseFont("宋体", 12, 0);pdfGenerator->drawText(QRectF(pageX, y, 500, 100), "第 1 页 Page", f, QColor(0,0,0), Qt::AlignLeft);y += 80;pdfGenerator->drawText(QRectF(pageX, y, 1444, 100), "共 2 页 This report includes page", f, QColor(0,0,0), Qt::AlignLeft);y += 100;// 标题1f = pdfGenerator->getBaseFont("宋体", 20, 8);pdfGenerator->drawText(QRectF(0, y, nPdfWidth, 120), "嘻嘻嘻这是一份关于检测相关的世界的详细报告哈哈", f, QColor(0,0,0), Qt::AlignCenter);y += 120;// 标题1英语f = pdfGenerator->getBaseFont("Times New Roman", 11, 8);QString english = "abc abc He he he, this is a detailed report about the world related to testing. Ha ha. abc abc";pdfGenerator->drawText(QRectF(0, y, nPdfWidth, 120), english, f, QColor(0,0,0), Qt::AlignCenter);y += 150;// 标题2f = pdfGenerator->getBaseFont("宋体", 30, 8);pdfGenerator->drawText(QRectF(0, y, nPdfWidth, 130), "一二三四五六报告", f, QColor(0,0,0), Qt::AlignCenter);y += 160;// 标题2英语f = pdfGenerator->getBaseFont("Times New Roman", 20, 12);pdfGenerator->drawText(QRectF(0, y, nPdfWidth, 130), "Tihs is a Report", f, QColor(0,0,0), Qt::AlignCenter);y += 160;// 报告编号f = pdfGenerator->getBaseFont("宋体", 10, 0);pdfGenerator->drawText(QRectF(0, y, nPdfWidth, 50), "报告编号:( 2025 )报告的 第 15 号", f, QColor(0,0,0), Qt::AlignCenter);y += 80;// Report No.f = pdfGenerator->getBaseFont("Times New Roman", 10, 0);pdfGenerator->drawText(QRectF(0, y, nPdfWidth, 50), "Report No.", f, QColor(0,0,0), Qt::AlignCenter);int nameX = 200; // 距离左边的距离int lineX = 500; // 横线距离左边的距离int lineWidth = 1322; // 横线宽度y += 100;for (int i = 0; i < 6; i++) {int tmpY = y + 30;// 你的名称f = pdfGenerator->getBaseFont();pdfGenerator->drawText(QRectF(nameX, y, 250, 60), "你的名称:", f, QColor(0,0,0), Qt::AlignLeft);y += 80;// 英文f = pdfGenerator->getBaseFont("Times New Roman", 10, 0);pdfGenerator->drawText(QRectF(nameX, y, 250, 60), "Your name", f, QColor(0,0,0), Qt::AlignLeft);y += 70;// 画横线f = pdfGenerator->getBaseFont();pdfGenerator->drawLine(QPointF(lineX, y), QPointF(lineX + lineWidth, y));// 画文本pdfGenerator->drawText(QRectF(lineX, tmpY, lineWidth, 80), "这是名字呀", f, QColor(0,0,0), Qt::AlignCenter);y += 30;// 自动换页处理
// if(y + 200 >= pdfGenerator->getPdfHeight()) {
// pdfGenerator->newPage();
// y = 10;
// }}y += 50;// 签发人f = pdfGenerator->getBaseFont();pdfGenerator->drawText(QRectF(nameX, y, 400, 60), "签发人:(签字)", f, QColor(0,0,0), Qt::AlignLeft);int dataX = 1111;// 发证日期f = pdfGenerator->getBaseFont();pdfGenerator->drawText(QRectF(dataX, y, 400, 60), "发证日期:", f, QColor(0,0,0), Qt::AlignLeft);y += 90;// 签发人 英文f = pdfGenerator->getBaseFont("Times New Roman", 10);pdfGenerator->drawText(QRectF(nameX, y, 400, 60), "Signature of leader", f, QColor(0,0,0), Qt::AlignLeft);// 发证日期 英文f = pdfGenerator->getBaseFont("Times New Roman", 10);pdfGenerator->drawText(QRectF(dataX, y, 400, 60), "lssued date", f, QColor(0,0,0), Qt::AlignLeft);y += 200;// 发证单位f = pdfGenerator->getBaseFont();pdfGenerator->drawText(QRectF(dataX, y, 600, 60), "发证单位:(盖章位置)", f, QColor(0,0,0), Qt::AlignLeft);y += 90;// 发证单位 英文f = pdfGenerator->getBaseFont("Times New Roman", 10);pdfGenerator->drawText(QRectF(dataX, y, 400, 60), "lssued by(stamp)", f, QColor(0,0,0), Qt::AlignLeft);y += 200;// 地址f = pdfGenerator->getBaseFont("宋体", 10);f.setBold(true);pdfGenerator->drawText(QRectF(nameX, y, 600, 66), "地址(Add):", f, QColor(0,0,0), Qt::AlignLeft);f = pdfGenerator->getBaseFont("宋体", 10);pdfGenerator->drawText(QRectF(nameX + 330, y, 800, 66), "广东省广州市天河区xx街道xx村xx号", f, QColor(0,0,0), Qt::AlignLeft);// 邮编f = pdfGenerator->getBaseFont("宋体", 10);f.setBold(true);pdfGenerator->drawText(QRectF(nameX + 1100, y, 600, 66), "邮编(Post Code):", f, QColor(0,0,0), Qt::AlignLeft);f = pdfGenerator->getBaseFont("宋体", 10);pdfGenerator->drawText(QRectF(nameX + 1550, y, 300, 66), "123456", f, QColor(0,0,0), Qt::AlignLeft);y += 100;// 电话f = pdfGenerator->getBaseFont("宋体", 10);f.setBold(true);pdfGenerator->drawText(QRectF(nameX, y, 600, 66), "电话(Tel):", f, QColor(0,0,0), Qt::AlignLeft);f = pdfGenerator->getBaseFont("宋体", 10);pdfGenerator->drawText(QRectF(nameX + 330, y, 800, 66), "002-123456789", f, QColor(0,0,0), Qt::AlignLeft);// 传真f = pdfGenerator->getBaseFont("宋体", 10);f.setBold(true);pdfGenerator->drawText(QRectF(nameX + 800, y, 600, 66), "传真(Fax):", f, QColor(0,0,0), Qt::AlignLeft);f = pdfGenerator->getBaseFont("宋体", 10);pdfGenerator->drawText(QRectF(nameX + 1050, y, 300, 66), "002-123456789", f, QColor(0,0,0), Qt::AlignLeft);y += 100;// 电子邮箱f = pdfGenerator->getBaseFont("宋体", 10);f.setBold(true);pdfGenerator->drawText(QRectF(nameX, y, 600, 66), "电子信箱(E-mail):", f, QColor(0,0,0), Qt::AlignLeft);f = pdfGenerator->getBaseFont("宋体", 10);pdfGenerator->drawText(QRectF(nameX + 400, y, 800, 66), "youxiang666@qq.com", f, QColor(0,0,0), Qt::AlignLeft);pdfGenerator->endPage();// 通过其它PDF阅读器来打开刚刚绘制的PDFQDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
四、源码分享
pdfgenerator.h
#ifndef PDF_GENERATOR_H
#define PDF_GENERATOR_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, QObject *parent = nullptr);explicit PdfGenerator(QObject *parent = nullptr);~PdfGenerator();qreal getPdfWidth();qreal getPdfHeight();/*** @brief getBaseFont 获得基本的字体* @param family* @param pointSize* @param weight* @return*/QFont getBaseFont(const QString &family = "宋体", int pointSize = 12, int weight = -1);/*** @brief setMargins 设置pdf边距,分别是 左-上-右-下* @param left* @param top* @param right* @param bottom*/void setMargins(qreal left, qreal top, qreal right, qreal bottom);/*** @brief setResolution 设置分辨率,一般为300* @param dpi*/void setResolution(int dpi = 300);/*** @brief newPage 新建下一页*/void newPage();/*** @brief beginPage 开始绘画* @return 成功返回true;失败返回false*/bool beginPage();/*** @brief endPage 结束会话* @return 成功返回true;失败返回false*/bool endPage();/*** @brief setFileName 设置pdf文件名,内部会open* @param fileName* @param size* @return*/bool setFileName(const QString &fileName, QPagedPaintDevice::PageSize size = QPagedPaintDevice::PageSize::A4);/*** @brief drawLine 绘制线段* @param start 起始坐标* @param end 结束坐标* @param color 线段颜色* @param width 线段宽度*/void drawLine(const QPointF &start, const QPointF &end, const QColor &color = QColor(0,0,0), qreal width = 2);/*** @brief drawText 绘制文字* @param rect 绘制的位置(矩形)* @param text 绘制的文本* @param font 绘制字体* @param color 字体颜色* @param align 对齐*/void drawText(const QRectF &rect, const QString &text, const QFont &font, const QColor &color = QColor(0,0,0), Qt::Alignment align = Qt::AlignCenter);/*** @brief drawImage 绘制图片* @param rect 绘制的位置(矩形)* @param imagePath 图片路径*/int drawImage(const QRectF &rect, const QString &imagePath);int drawImage(const QRectF &rect, const QPixmap &pixmap);int drawImage(const QRectF &rect, const QImage &image);/*** @brief drawRect 绘制矩形* @param rect 绘制的位置(矩形)* @param borderColor 边框的颜色* @param borderWidth 边框宽度* @param fillColor 填充的颜色,默认透明,不填充*/void drawRect(const QRectF &rect, const QColor &borderColor = QColor(0,0,0), qreal borderWidth = 2, const QColor &fillColor = Qt::transparent);/*** @brief drawEllipse 绘制椭圆* @param rect 绘制的位置(矩形)* @param borderColor 边框的颜色* @param borderWidth 边框宽度* @param fillColor 填充的颜色,默认透明,不填充*/void drawEllipse(const QRectF &rect, const QColor &borderColor = QColor(0,0,0), qreal borderWidth = 2, const QColor &fillColor = Qt::transparent);/*** @brief drawPolygon 画三角形,三角形在矩形区域内* @param rect 绘制的位置(矩形)* @param borderColor 边框的颜色* @param borderWidth 边框宽度* @param fillColor 填充的颜色,默认透明,不填充*/void drawPolygon(const QRectF &rect, const QColor &borderColor = QColor(0,0,0), qreal borderWidth = 2, const QColor &fillColor = Qt::transparent);// 想设计其他绘制接口继续往下加private:QPdfWriter *m_writer = nullptr;QPainter *m_painter = nullptr;/// pdf可绘制区域QRect m_pageRect;/// pdf文件QFile m_pdfFile;
};#endif // PDF_GENERATOR_H
pdfgenerator.cpp
#include "pdfgenerator.h"
#include <QtDebug>PdfGenerator::PdfGenerator(const QString &fileName, QPagedPaintDevice::PageSize size, QObject *parent) : QObject (parent)
{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(QObject *parent) : QObject (parent)
{}PdfGenerator::~PdfGenerator()
{if (m_painter) {if (m_painter->isActive()){m_painter->end();}delete m_painter;}if (m_writer) {m_writer->deleteLater();}
}qreal PdfGenerator::getPdfWidth()
{return m_pageRect.width();
}qreal PdfGenerator::getPdfHeight()
{return m_pageRect.height();
}QFont PdfGenerator::getBaseFont(const QString &family, int pointSize, int weight)
{QFont f(family, pointSize, weight);return f;
}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()); // 更新绘制区域
}void PdfGenerator::setResolution(int dpi)
{m_writer->setResolution(dpi);
}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;
}bool PdfGenerator::setFileName(const QString &fileName, QPagedPaintDevice::PageSize size)
{m_pdfFile.setFileName(fileName);// 打开创建并以写的方式打开文件if(!m_pdfFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {return false;}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());return true;
}// 绘制线段
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();
}// 绘制图片(根据大小比例,来放大缩小图片)
int PdfGenerator::drawImage(const QRectF &rect, const QString &imagePath)
{if (!m_painter->isActive())return -10;QPixmap pixmap;if (!pixmap.load(imagePath)) {return -1;}int nPdfWidth = m_pageRect.width();int imageBorder = rect.width();float x = (float)(nPdfWidth - imageBorder * 2) / (float)pixmap.width();pixmap = pixmap.scaled(nPdfWidth - imageBorder * 2, x * pixmap.height(), Qt::IgnoreAspectRatio); //根据大小比例,来放大缩小图片m_painter->drawPixmap(imageBorder, static_cast<int>(rect.y()), pixmap);return pixmap.height();
}int PdfGenerator::drawImage(const QRectF &rect, const QPixmap &pixmap)
{if (!m_painter->isActive())return -1;if (pixmap.isNull())return -1;int nPdfWidth = m_pageRect.width();int imageBorder = rect.width();float x = (float)(nPdfWidth - imageBorder * 2) / (float)pixmap.width();QPixmap pixmapTmp = pixmap.scaled(nPdfWidth - imageBorder * 2, x * pixmap.height(), Qt::IgnoreAspectRatio); //根据大小比例,来放大缩小图片m_painter->drawPixmap(imageBorder, static_cast<int>(rect.y()), pixmapTmp);return pixmapTmp.height();
}int PdfGenerator::drawImage(const QRectF &rect, const QImage &image)
{if (!m_painter->isActive())return -1;if (image.isNull())return -1;int nPdfWidth = m_pageRect.width();int imageBorder = rect.width();float x = (float)(nPdfWidth - imageBorder * 2) / (float)image.width();QImage imageTmp = image.scaled(nPdfWidth - imageBorder * 2, x * image.height(), Qt::IgnoreAspectRatio); //根据大小比例,来放大缩小图片m_painter->drawImage(rect, image);return image.height();
}// 绘制矩形(支持填充)
void PdfGenerator::drawRect(const QRectF &rect, const QColor &borderColor, qreal borderWidth, const QColor &fillColor)
{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 &borderColor, qreal borderWidth, const QColor &fillColor)
{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();
}void PdfGenerator::drawPolygon(const QRectF &rect, const QColor &borderColor, qreal borderWidth, const QColor &fillColor)
{if (!m_painter->isActive())return;QPen pen(borderColor, borderWidth); // 底边线宽为5m_painter->setPen(pen);QBrush brush(fillColor);m_painter->setBrush(brush);QPoint points[3] = {QPoint(rect.x(), rect.y() + rect.height()), // 左下角点QPoint(rect.x() + rect.width(), rect.y() + rect.height()), // 右下角点QPoint((rect.width() + rect.x() + rect.x()) / 2, rect.y()) // 上顶点};m_painter->drawPolygon(points, 3);
}
相关文章:
QT 使用QPdfWriter和QPainter绘制PDF文件
QT如何生产pdf文件,网上有许多文章介绍,我也是看了网上的文章,看他们的代码,自己琢磨琢磨,才有了本编博客; 其他什么就不详细说了,本篇博客介绍的QPdfWriter和QPainter绘制PDF文件;…...
解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs- Manus技术解密
解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs- Manus技术解密 如果你从应用程序的角度讲,但是如果我们从模型的角度讲,我们必须让模型既具有这种思考的能力,也具有产出这种最佳的action的这种能力。而且…...
网络安全-等级保护(等保) 2-4 GB/T 22239-2019 《信息安全技术 网络安全等级保护基础要求》-2019-05-10发布【现行】
################################################################################ 等级确定之后,需要根据不同的安全等级满足相关建设要求,《等级保护基础要求》明确了安全物理环境、安全通信网络、安全区域边界、安全计算环境、安全管理中心、安全管…...
Ansys Zemax | 在 MATLAB 或 Python 中使用 ZOS-API 进行光线追迹的批次处理
附件下载 联系工作人员获取附件 这篇文章会说明如何在 MATLAB 或 Python 中以 Zemax OpticStudio 应用程式界面 (ZOS-API)处理光线数据库(Ray Database, ZRD)档案,过程中我们将使用ZRDLoader.dll。本文提供了在 Matlab 中批次处理序列光线追迹(一般、归一化、偏振…...
多链互操作性标准解析:构建下一代区块链互联生态
引言 在区块链技术快速演进的今天,“多链宇宙”已成为不可逆的趋势。然而,链与链之间的孤立性导致流动性割裂、开发成本高昂和用户体验碎片化。互操作性标准的制定,正是打破这一僵局的核心钥匙。本文将深入探讨主流互操作性协议的技术架构、…...
openEuler24.03 LTS下安装MySQL8.0.42
目录 前提步骤 删除原有mysql及maridb数据库 安装MySQL 启动MySQL 启动查看MySQL状态 设置MySQL开机自启动 查看登录密码 登录MySQL 修改密码及支持远程连接 远程连接MySQL 前提步骤 拥有openEuler24.03 LTS环境,可参考:Vmware下安装openEule…...
React 轻量级富文本编辑器推荐(中文版)
以下是几款适合集成到 React 项目中的轻量级富文本编辑器,特别针对中文用户优化推荐: 超轻量级选择(小于100KB) 1. react-simplemde-editor(Markdown编辑器) 特点:专为 Markdown 设计…...
React 第四十一节Router 中 useActionData 使用方法案例以及注意事项
一、useActionData前言 useActionData 是 React Router 提供的一个钩子函数,用于获取在路由的 action 函数中返回的数据。它通常与表单提交(通过 <Form> 组件)配合使用,用于处理表单提交后的服务器响应数据(如错…...
西门子 Teamcenter13 Eclipse RCP 开发 1 工具栏
西门子 Teamcenter13 Eclipse RCP 开发 1 工具栏 1 配置文件2 插件控制3 命令框架 1 配置文件 在 Teamcenter 13 Eclipse RCP 开发中,plugin.xml 是插件的核心配置文件,定义了插件的: 1、唯一身份(ID、版本)。 2、所…...
【python实用小脚本-63】每天花费2小时修复黑白照片,Python一键转换,节省90%时间(建议收藏)
一、应用场景故事 上周,我的朋友小李从家里翻出了一堆老照片,这些照片大多是彩色的,但他想把它们转换成黑白风格,让照片更有复古感。他尝试用Photoshop一张张处理,但花了整整一个周末,才处理了不到一半的照…...
R语言的专业网站top5推荐
李升伟 以下是学习R语言的五个顶级专业网站推荐,涵盖教程、社区、资源库和最新动态: 1.R项目官网 (r-project.org) R语言的官方网站,提供软件下载、文档、手册和常见问题解答。特别适合初学者和高级用户,是获取R语言核心资源的…...
Apache JMeter API 接口压测技术指南
文章目录 前言技术积累JMeter 简介适用场景JMeter 核心组件 安装与配置线程组压测逐步加压压测安装相应jmeter 插件创建测试计划生成压测HTML 总结 前言 Apache JMeter 是一款开源的性能测试工具,主要用于对 Web 应用、API 接口、数据库等进行负载和压力测试。本指…...
【Java实战】IO流(转换流,打印流,数据流,序列化流)
引出问题 不同编码读取出现的乱码问题 如果是代码编码被读取的文本文件的编码是一致的,使用字符流读取文本文件时不会出现乱码; 如果不一致,使用字符流读取文本文件就会出现乱码。 public class BufferedReader{ public static void main(S…...
Python课程及开源项目推荐
Python课程及开源项目推荐 摘要:学习 Python 是一个非常好的选择,因为它是一种功能强大且易于上手的编程语言,广泛应用于数据分析、数据可视化、机器学习、网络爬虫等领域。以下是针对 Coursera 上 Python 课程和专业证书的推荐,以…...
内网互通原则详解!
目录 前言1. 路由 (Routing): 谁去哪儿找谁?🗺️2. 防火墙与安全组 (Firewalls & Security Groups): 门卫大爷和保安系统!👮♂️🚪3. 内网 DNS (Internal DNS): 小区的通讯录/电话本!📒&a…...
[Harmony]大文件持久化
1.添加权限 在module.json5文件中添加权限 "requestPermissions": [{"name": "ohos.permission.READ_WRITE_USER_FILE", // 读写用户数据"reason": "$string:read_write_user_file_reason","usedScene": {"…...
C 语言实战:使用二维数组进行学生成绩统计与分析
各类资料学习下载合集 https://pan.quark.cn/s/8c91ccb5a474 在处理表格型数据时,二维数组是 C 语言中一种非常直观且强大的工具。学生成绩单就是一个典型的二维数据:每一行代表一个学生,每一列代表一门科目。本文将通过一个具体的案例,演示如何利用二维数组来存…...
[学习]RTKLib详解:tle.c(系列终章)
本文是 RTKLlib详解 系列文章的一篇,目前该系列文章还在持续总结写作中,以发表的如下,有兴趣的可以翻阅。 [学习] RTKlib详解:功能、工具与源码结构解析 [学习]RTKLib详解:pntpos.c与postpos.c [学习]RTKLib详解&…...
体重秤出口日本的计量认证介绍,体脂秤出口日本“正”认证介绍
什么是家庭专用测量仪器? 家庭专用测量仪器是一种非自动秤,主要用于普通消费者的日常生活,并且刻度为10 mg或更大,并且秤号的刻度为100或更大,满足以下条件的: 通用秤 是一种非自动秤,重量超过…...
【hadoop】Flume的相关介绍
1 概述 Flume是Cloudera开发的一个分布式的、可靠的、高可用的系统,它能够将不同数据源的海量日志数据进行高效收集、聚合、移动,最后存储到一个中心化的数据存储系统中。随着互联网的发展,特别是移动互联网的兴起,产生了海量的用…...
图片、音频、视频都能转?简鹿格式工厂了解一下
我们每天都会接触到各种各样的音视频和图片文件。无论是拍摄的照片、录制的视频,还是下载的音频资源,它们往往以不同的格式存在——有些适合分享,有些适合编辑,而有些则仅限特定设备或平台使用。格式不统一的问题,正在…...
doris节点数量规划
1.FE 节点数量 FE 节点主要负责用户请求的接入、查询解析规划、元数据管理及节点管理等工作。 对于生产集群,一般建议部署至少 3 个节点的 FE 以实现高可用环境。FE 节点分为以下两种角色: Follower 节点:参与选举操作,…...
Android Studio中Gradle 7.0上下项目配置及镜像修改
最近在打包一个测试项目的时候,使用的android studio版本比较老,后来升级到2024发现了一些小问题。可能对于安卓程序员来说,司空见惯,但对我这样的安卓小白,可把我折腾了半天。现在记录下来,供比我还小白的…...
Android Studio中Gradle中Task列表显示不全解决方案
问题现象 解决方案 File -> Settings -> Experimental ->勾选Configure all Gradle tasks during Gradle Sync(this can make Gradle Sync slower) 参考文章 Android执行build-gradle中的任务Task...
OneNote内容太多插入标记卡死的解决办法
OneNote内容太多插入标记卡死的解决办法 针对平板电脑的OneNote用户适合此类情况: 当向电脑导入几百页pdf可以正常使用,唯独插入标记的时候OneNote直接罢工,只能关闭。关闭时还可能会出现0x000000fxxxxx的错误。 注:仅对于平板…...
vue3:十三、分类管理-表格--行内按钮---行删除、批量删除实现功能实现
一、实现效果 增加行内按钮的样式效果,并且可以根绝父组件决定是否显示 增加行内删除功能、批量删除功能 二、增加行内按钮样式 1、增加视图层按钮 由于多个表格都含有按钮功能,所以这里直接在子组件中加入插槽按钮 首先增加表格行<el-table-column></el-table-…...
Python类的力量:第五篇:魔法方法与协议——让类拥有Python的“超能力”
文章目录 前言:从“普通对象”到“Python原生公民”的进化之路 一、魔法方法:赋予对象“超能力”的基因1. 构造与析构:对象生命周期的“魔法开关”2. 字符串表示:对象的“自我介绍”3. 运算符重载:让对象支持“数学魔法…...
R S的EMI接收机面板
图片摘自R & S官网。 根据您提供的第一张图(设备前面板带屏幕的图像),这是 Rohde & Schwarz ESRP7 EMI Test Receiver 的正面显示界面,我将对屏幕上显示的参数逐项进行解读: 🖥️ 屏幕参数解读 左…...
pytorch nn.RNN demo
之前已经讲过关于RNNCell的实现了. 这里用LLM写了一个简单的nn.RNN demo: import torch import torch.nn as nn# 设置随机种子以便结果可复现 torch.manual_seed(42)# 定义模型参数 input_size 4 # 输入特征维度 hidden_size 8 # 隐藏层维度 num_layer…...
高防服务器流量“清洗”什么意思
在当今数字化的时代,网络安全成为了备受关注的焦点。其中,高防服务器流量“清洗”这个概念,对于许多朋友来说可能还比较陌生。今天,就让我们一起来揭开它神秘的面纱。 首先,咱们得明白,高防服务器流量“清…...
Unity3D开发AI桌面精灵/宠物系列 【六】 人物模型 语音口型同步 LipSync 、梅尔频谱MFCC技术、支持中英文自定义编辑- 基于 C# 语言开发
Unity3D开发AI桌面精灵/宠物系列 【六】 人物模型 语音口型同步 LipSync 、梅尔频谱MFCC技术 C# 语言开发 该系列主要介绍怎么制作AI桌面宠物的流程,我会从项目开始创建初期到最终可以和AI宠物进行交互为止,项目已经开发完成,我会仔细梳理一下…...
Java详解LeetCode 热题 100(17):LeetCode 41. 缺失的第一个正数(First Missing Positive)详解
文章目录 1. 题目描述2. 理解题目3. 解法一:排序法(不满足题目要求)3.1 思路3.2 Java代码实现3.3 代码详解3.4 复杂度分析3.5 不足之处 4. 解法二:哈希表法4.1 思路4.2 Java代码实现4.3 代码详解4.4 复杂度分析4.5 不足之处 5. 解…...
Kafka消息路由分区机制深度解析:架构设计与实现原理
一、消息路由系统的核心架构哲学 1.1 分布式系统的三元悖论 在分布式消息系统的设计过程中,架构师需要平衡三个核心诉求:数据一致性、系统可用性和分区容忍性。Kafka的分区路由机制本质上是对CAP定理的实践解: 一致性维度:通过…...
用C语言实现了——一个基于顺序表的插入排序演示系统
一、知识要点、 插入排序是一种简单直观的排序算法,它的工作方式类似于我们整理扑克牌。 基本原理: 插入排序通过构建有序序列来工作。它每次从无序序列中取出一个元素,然后将其插入到已排序序列的适当位置。这个过程重复进行,…...
linux libdbus使用案例
以下是一个基于 Linux libdbus 的详细指南,包含服务端和客户端的完整代码示例,涵盖 方法调用、信号发送 和 异步消息处理。libdbus 是 D-Bus 的底层 C 库,直接操作 D-Bus 协议,适合需要精细控制的场景。 1. libdbus 的核心机制 连接管理:通过 dbus_bus_get 连接系统总线或…...
Apple Vision Pro空间视频创作革命:从180度叙事到沉浸式语法的重构——《Adventure》系列幕后技术深度解析
🌌 引言:沉浸式媒体的“语法实验室” Apple Vision Pro的推出标志着空间计算时代的到来,而《Adventure》系列作为其原生内容标杆,正在成为沉浸式叙事的“语法实验室”。导演Charlotte Mikkelborg与播客主持人Kent Bye的对话揭示了这一领域的技术突破、创作挑战与行业生态…...
[特殊字符] 苍穹外卖项目中的 WebSocket 实战:实现来单与催单提醒功能
🚀 苍穹外卖项目中的 WebSocket 实战:实现来单与催单提醒功能 在现代 Web 应用中,实时通信成为提升用户体验的关键技术之一。WebSocket 作为一种在单个 TCP 连接上进行全双工通信的协议,被广泛应用于需要实时数据交换的场景&#…...
【C/C++】深度解析C++ Allocator:优化内存管理的关键
文章目录 深度解析C Allocator:优化内存管理的关键1 默认 std::allocator2 自定义 Allocator3 自定义 Allocator 的实现3.1 基本结构3.2 使用自定义 Allocator 4 关键特性详解4.1 rebind 机制4.2 状态化 Allocator 5 应用示例:内存池 Allocator5.1 简单内…...
gitlab+portainer 实现Ruoyi Vue前端CI/CD
1. 场景 最近整了一个Ruoyi Vue 项目,需要实现CICD,经过一番坎坷,最终达成,现将技术要点和踩坑呈现。 具体操作流程和后端大同小异,后端操作参考连接如下: https://blog.csdn.net/leinminna/article/detai…...
CAPL编程系列_04
1_ 测试模块TestModule:基本使用 1)在Simulation Setup 中创建并配置 Test Module节点 2)编写测试脚本 【1】测试用例函数(testcase):实现具体测试逻辑 【2】主测试函数(Main Test)&…...
Weblogic SSRF漏洞复现(CVE-2014-4210)【vulhub靶场】
漏洞概述: Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis、fastcgi等脆弱组件。 漏洞形成原因: WebLogic Server 的 UDDI 组件(uddiexplorer.war)中的 SearchPublicR…...
科技的成就(六十八)
623、杰文斯悖论 杰文斯悖论是1865年经济学家威廉斯坦利杰文斯提出的一悖论:当技术进步提高了效率,资源消耗不仅没有减少,反而激增。例如,瓦特改良的蒸汽机让煤炭燃烧更加高效,但结果却是煤炭需求飙升。 624、代码混…...
知从科技闪耀2025上海车展:以创新驱动未来出行新篇章
上海,2025年4月23日——全球汽车科技领域的年度盛会——2025上海国际汽车工业展览会(简称“上海车展”)于5月2日圆满落幕。作为智能汽车软件与系统解决方案的领军企业,知从科技受邀参展,并在活动期间全方位展示了其在智…...
【iOS安全】Dopamine越狱 iPhone X iOS 16.6 (20G75) | 解决Jailbreak failed with error
Dopamine越狱 iPhone X iOS 16.6 (20G75) Dopamine兼容设备 参考:https://www.bilibili.com/opus/977469285985157129 A9 - A11(iPhone6s-X):iOS15.0-16.6.1 A12-A14(iPhoneXR-12PM…...
医疗数据迁移质量与效率的深度研究:三维六阶框架与实践创新
引言 随着医疗信息化建设的深入推进,医疗数据作为医疗机构的核心资产,其价值与日俱增。在医院信息系统升级、迁移或整合过程中,数据迁移的质量与效率直接关系到医疗服务的连续性、患者信息的安全性以及医院运营的稳定性。传统数据迁移方法往往面临时间长、风险高、成本大等…...
[6-8] 编码器接口测速 江协科技学习笔记(7个知识点)
1 2 在STM32微控制器的定时器模块中,CNT通常指的是定时器的计数器值。以下是CNT是什么以及它的用途: 是什么: • CNT:代表定时器的当前计数值。在STM32中,定时器从0开始计数,直到达到预设的自动重装载值&am…...
java类加载阶段与双亲委派机制
java执行过程:.java->.class->然后被jvm加载解释执行。 一、类加载机制的三个阶段 加载(Loading) 任务:通过类的全限定名获取二进制字节流(如从文件系统、网络等),将字节流转换为方…...
医院网络安全托管服务(MSS)深度解读与实践路径
医疗行业网络安全挑战与MSS的应运而生 医疗行业在数智化转型的过程中面临着前所未有的网络安全挑战。根据2025年的最新数据,医疗行业将面临大量网络攻击,其中高达91%与勒索软件有关,且45%的数据泄露事件源于第三方供应商。医疗机构的平均数据…...
计算图存储采用矩阵吗,和张量关系
计算图存储采用矩阵吗,和张量关系 计算图的存储方式与张量的关系 一、计算图的存储方式 计算图(Computational Graph)是一种用于描述数学运算的有向无环图(DAG),其节点代表运算(如加减乘除、矩阵乘法、激活函数等),边代表运算的输入和输出(通常是张量)。计算图的…...
RPA 自动化实现自动发布
📕我是廖志伟,一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》(基础篇)、(进阶篇)、(架构篇)清华大学出版社签约作家、Java领域优质创作者、CSDN博客专家、…...