|
|
@@ -0,0 +1,97 @@
|
|
|
+package cn.start.tz.module.pressure2.util;
|
|
|
+
|
|
|
+import cn.start.tz.module.infra.api.file.FileApi;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang.StringUtils;
|
|
|
+import org.apache.pdfbox.multipdf.PDFMergerUtility;
|
|
|
+import org.apache.pdfbox.pdmodel.PDDocument;
|
|
|
+import org.apache.pdfbox.pdmodel.PDPage;
|
|
|
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|
|
+
|
|
|
+import java.io.ByteArrayInputStream;
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+
|
|
|
+/**
|
|
|
+ * PDF 合并工具类:将模板 PDF 与 manualUrl 对应的附件合并,并添加页间分割线
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public class PdfMergeUtils {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成检验方案 PDF:模板 PDF + 可选附件 PDF 合并,并添加页间分割线
|
|
|
+ *
|
|
|
+ * @param templatePdfBytes 模板 PDF 字节数组
|
|
|
+ * @param manualUrl 附件文件路径(可为空)
|
|
|
+ * @param fileApi 文件服务 API
|
|
|
+ * @return 合并后的 PDF 字节数组
|
|
|
+ */
|
|
|
+ public static byte[] buildInspectionPlanPdf(byte[] templatePdfBytes, String manualUrl, FileApi fileApi) {
|
|
|
+ byte[] mergedBytes = templatePdfBytes;
|
|
|
+
|
|
|
+ // 如果有关联附件,合并到 PDF 中
|
|
|
+ if (StringUtils.isNotEmpty(manualUrl)) {
|
|
|
+ try {
|
|
|
+ ByteArrayOutputStream manualOutputStream = new ByteArrayOutputStream();
|
|
|
+
|
|
|
+ if (manualUrl.endsWith(".doc") || manualUrl.endsWith(".docx")) {
|
|
|
+ byte[] wordBytes = fileApi.getFileByPath(manualUrl).getData();
|
|
|
+ if (wordBytes != null && wordBytes.length > 0) {
|
|
|
+ manualOutputStream = WordToPdfUtils.doc2pdfOutStream(wordBytes);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ byte[] fileBytes = fileApi.getFileByPath(manualUrl).getData();
|
|
|
+ if (fileBytes != null && fileBytes.length > 0) {
|
|
|
+ manualOutputStream.write(fileBytes);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (manualOutputStream.size() > 0) {
|
|
|
+ ByteArrayOutputStream mergeOutputStream = new ByteArrayOutputStream();
|
|
|
+ PDFMergerUtility mergerUtility = new PDFMergerUtility();
|
|
|
+ mergerUtility.addSource(new ByteArrayInputStream(templatePdfBytes));
|
|
|
+ mergerUtility.addSource(new ByteArrayInputStream(manualOutputStream.toByteArray()));
|
|
|
+ mergerUtility.setDestinationStream(mergeOutputStream);
|
|
|
+ mergerUtility.mergeDocuments(null);
|
|
|
+ mergedBytes = mergeOutputStream.toByteArray();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[buildInspectionPlanPdf] 合并附件 PDF 失败: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加页间分割线
|
|
|
+ try {
|
|
|
+ mergedBytes = addPageDividers(mergedBytes);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[buildInspectionPlanPdf] 添加页间分割线失败: {}", e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return mergedBytes;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 为 PDF 每一页之间添加分割线
|
|
|
+ */
|
|
|
+ private static byte[] addPageDividers(byte[] pdfBytes) throws IOException {
|
|
|
+ try (PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes))) {
|
|
|
+ int totalPages = document.getNumberOfPages();
|
|
|
+ for (int i = 0; i < totalPages - 1; i++) {
|
|
|
+ PDPage page = document.getPage(i);
|
|
|
+ try (PDPageContentStream contentStream = new PDPageContentStream(document, page,
|
|
|
+ PDPageContentStream.AppendMode.APPEND, true, true)) {
|
|
|
+ float pageWidth = page.getMediaBox().getWidth();
|
|
|
+ float dividerY = 15f;
|
|
|
+ contentStream.setStrokingColor(0.5f, 0.5f, 0.5f);
|
|
|
+ contentStream.setLineWidth(1f);
|
|
|
+ contentStream.moveTo(0, dividerY);
|
|
|
+ contentStream.lineTo(pageWidth, dividerY);
|
|
|
+ contentStream.stroke();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
|
+ document.save(outputStream);
|
|
|
+ return outputStream.toByteArray();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|