QT打印 文本 + png公章
之前看到这个链接很有意思https://blog.csdn.net/wastelandboy/article/details/124535680虽然很美但是我想直接一个pdf 上 png 打印就好了因为这段代码免费上面那个控件资源目前没有获取到。代码如下void CaiGou::drawContractContent(QPainter *painter, const QJsonObject payload) { if (!painter || !painter-isActive()) return; painter-setRenderHint(QPainter::Antialiasing); // 1. 物理参数获取打印机当前像素宽高 int pw m_printer-width(); int ph m_printer-height(); // 2. 比例适配系数基准宽度 800 double factor pw / 800.0; auto s [factor](int val) - int { return static_castint(val * factor); }; // --- 字体配置 --- QString fontName 黑体; // ✅ 改为黑体 QFont titleFont(fontName, 22, QFont::Bold); QFont normalFont(fontName, 14); // ✅ 14px QFont tableHeaderFont(fontName, 14, QFont::Bold); // 3. 绘制标题 int yPos s(50); painter-setFont(titleFont); painter-drawText(QRect(0, yPos, pw, s(40)), Qt::AlignCenter, 采 购 合 同); // 4. 基础信息 yPos s(60); int leftCol s(50); painter-setFont(normalFont); painter-drawText(leftCol, yPos, 日 期 payload.value(date).toString()); painter-drawText(pw / 2 s(20), yPos, 订单号 payload.value(orderNo).toString()); yPos s(25); painter-drawText(leftCol, yPos, 甲 方 payload.value(jiaFang).toString()); yPos s(25); painter-drawText(leftCol, yPos, 乙 方 payload.value(yiFang).toString()); yPos s(30); painter-drawText(leftCol, yPos, 商品信息如下); // 5. 表格参数 yPos s(20); int tableLeft s(40); int tableWidth pw - tableLeft * 2; QVectorint colWidths { static_castint(tableWidth * 0.35), static_castint(tableWidth * 0.15), static_castint(tableWidth * 0.15), static_castint(tableWidth * 0.15), static_castint(tableWidth * 0.20) }; QStringList headers {规格、描述, 数量/吨, 单价, 总额, 备注}; int baseRowHeight s(35); // 设置边框笔 painter-setPen(QPen(Qt::black, factor * 1.5, Qt::SolidLine)); // A. 绘制表头 painter-setFont(tableHeaderFont); int xPos tableLeft; for (int i 0; i headers.size(); i) { QRect cellRect(xPos, yPos, colWidths[i], baseRowHeight); painter-drawRect(cellRect); painter-drawText(cellRect, Qt::AlignCenter, headers[i]); xPos colWidths[i]; } yPos baseRowHeight; // B. 绘制数据行 painter-setFont(normalFont); QJsonArray goods payload.value(goods).toArray(); for (int i 0; i goods.size(); i) { // 分页检查预留底部空间至少 150px if (yPos baseRowHeight ph - s(150)) { m_printer-newPage(); yPos s(40); // 新页顶部留白 // 重新绘制表头增强体验 painter-setFont(tableHeaderFont); int x tableLeft; for (int j 0; j headers.size(); j) { QRect r(x, yPos, colWidths[j], baseRowHeight); painter-drawRect(r); painter-drawText(r, Qt::AlignCenter, headers[j]); x colWidths[j]; } yPos baseRowHeight; painter-setFont(normalFont); } QJsonObject row goods[i].toObject(); QString priceStr row.value(price).toString(); bool isTotal priceStr.contains(合计) || priceStr.contains(总金额); QStringList rowData; if (isTotal) { rowData 合计 合同总额 row.value(total).toString() ; } else { rowData row.value(desc).toString() row.value(qty).toString() row.value(price).toString() row.value(total).toString() row.value(memo).toString(); } // ✅ 正确计算多行所需高度关键修复 int maxRowHeight baseRowHeight; for (int col 0; col rowData.size(); col) { QRect rect(0, 0, colWidths[col], 10000); // 高度足够大以允许换行 int flags Qt::TextWordWrap; if (col 0) flags | Qt::AlignLeft; else flags | Qt::AlignCenter; QRect bound painter-fontMetrics().boundingRect(rect, flags, rowData[col]); int neededHeight bound.height() s(8); // 上下留点间距 if (neededHeight maxRowHeight) { maxRowHeight neededHeight; } } // 绘制单元格 xPos tableLeft; for (int col 0; col rowData.size(); col) { QRect cellRect(xPos, yPos, colWidths[col], maxRowHeight); painter-drawRect(cellRect); int alignFlags Qt::TextWordWrap; if (col 0) { alignFlags | Qt::AlignLeft | Qt::AlignVCenter; } else { alignFlags | Qt::AlignCenter; } painter-drawText(cellRect, alignFlags, rowData[col]); xPos colWidths[col]; } yPos maxRowHeight; // ✅ 累加真实高度 } // 记录表格结束位置避免后续内容重叠 int tableEndY yPos; Q_UNUSED(tableEndY); // 记录表格结束位置 int currentY yPos s(25); // 表格与条款间安全间距 // 6. 合同条款动态高度绘制 painter-setFont(normalFont); QStringList termLines; termLines 1.产品交付方式产品按乙方运输方式运至甲方指定地点交付 交货地址广州市南沙区东涌镇广珠路3-13号 联系人沈生 联系电话18739631062 2.交货期限请乙方按以上备注栏要求的时间完成产品之交付。 3.付款方式甲方在产品发货前付清请乙方至少提前一天通知甲方。 4.产品验收产品到货签收后由甲方进行产品验收验收数量以甲方清点数量为准验收不合格的甲方有权要求乙方退换。; // 交货地址 payload.value(address).toString() // 建议从payload获取地址 for (const QString line : termLines) { // 动态计算这一行可能包含自动换行的高度 QRect boundingRect painter-fontMetrics().boundingRect( QRect(tableLeft, currentY, tableWidth, 1000), Qt::AlignLeft | Qt::TextWordWrap, line ); // 绘制该段文本 painter-drawText(boundingRect, Qt::AlignLeft | Qt::TextWordWrap, line); // 关键将 yPos 移动到当前文本块底部并留出小行间距 currentY boundingRect.height() s(5); } // 7. 签名栏基于上述动态计算后的 currentY currentY s(40); // 条款与签名间增加较明显的间距 int sigWidth tableWidth / 2 20; int sigLineHeight s(30); // 甲方乙方行 【带公章】 painter-drawText(tableLeft, currentY, 甲方 payload.value(jiaFang).toString()); painter-drawText(tableLeft sigWidth, currentY, 乙方 payload.value(yiFang).toString()); currentY sigLineHeight; painter-drawText(tableLeft, currentY, 代表); painter-drawText(tableLeft sigWidth, currentY, 代表); currentY sigLineHeight; painter-drawText(tableLeft, currentY, 日期); painter-drawText(tableLeft sigWidth, currentY, 日期); // 电子公章逻辑绘制在“日期”文字的下方 // 基础配置开启抗锯齿和高质量缩放确保印章边缘平滑 painter-save(); painter-setRenderHint(QPainter::Antialiasing); painter-setRenderHint(QPainter::SmoothPixmapTransform); painter-setOpacity(0.95); // 稍微带一点点透明盖在白纸上更真实 int sealW s(140); // 公章宽度 int sealH s(140); // 公章高度 int sealY currentY s(5); // 统一的 Y 轴起始点日期下方 5px // --- 1. 甲方公章 --- QImage jiaImage(:/pic/year.png); if (!jiaImage.isNull()) { // X 坐标甲方文字起始位置 偏移 int jiaX tableLeft s(100); painter-drawImage(QRect(jiaX, sealY, sealW, sealH), jiaImage); } // --- 2. 乙方公章 --- QImage yiImage(:/pic/mus4.png); if (!yiImage.isNull()) { // X 坐标乙方文字起始位置 (tableLeft sigWidth) 相同偏移量 int yiX tableLeft sigWidth s(100); painter-drawImage(QRect(yiX, sealY, sealW, sealH), yiImage); } painter-restore(); // 恢复状态 // 公章处理结束 }运行效果如下pspng要透明背景否则代码还需要做透明处理