From dd30506fe9b4c22da87f5f63877c9df10aff7d01 Mon Sep 17 00:00:00 2001 From: jiangs <373297395@qq.com> Date: Fri, 28 Nov 2025 09:09:49 +0800 Subject: [PATCH] =?UTF-8?q?pdf=E6=8A=A5=E5=91=8AA4=E5=88=87=E5=89=B2A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lis-interfaceCommon/pom.xml | 6 + .../utils/PdfPaperConverter.java | 114 ++++++++++++++++++ pom.xml | 8 ++ .../service/impl/ZybgcxServcieImpl.java | 24 ++-- 4 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/PdfPaperConverter.java diff --git a/lis-interfaceCommon/pom.xml b/lis-interfaceCommon/pom.xml index dc457d0..2a92d71 100644 --- a/lis-interfaceCommon/pom.xml +++ b/lis-interfaceCommon/pom.xml @@ -75,6 +75,12 @@ spring-boot-starter-websocket + + org.apache.pdfbox + pdfbox + + + diff --git a/lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/PdfPaperConverter.java b/lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/PdfPaperConverter.java new file mode 100644 index 0000000..776a293 --- /dev/null +++ b/lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/PdfPaperConverter.java @@ -0,0 +1,114 @@ +package com.czlis.interfaceCommon.utils; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.multipdf.LayerUtility; +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Base64; + +public class PdfPaperConverter { + + private static final float A4_WIDTH = 595f; // A4标准宽度(pt) + private static final float A4_HEIGHT = 842f; // A4标准高度(pt) + private static final float A5_HEIGHT = 420f; // A5高度(保留A4宽度) + private static final float TOLERANCE = 10f; // 尺寸判断容差 + + + // 新增:粗略判断Base64 PDF是A4还是A5(高度> A5_HEIGHT即视为A4) + public static boolean isBase64PdfA4(String base64Pdf) { + if (base64Pdf == null || base64Pdf.trim().isEmpty()) { + return false; // 空字符串直接返回非A4 + } + + byte[] pdfBytes = null; + try { + // 尝试解码Base64(失败则视为非A4) + pdfBytes = cn.hutool.core.codec.Base64.decode(base64Pdf); + } catch (Exception e) { + return false; + } + + try (PDDocument doc = PDDocument.load(new ByteArrayInputStream(pdfBytes))) { + if (doc.getNumberOfPages() == 0) { + return false; // 无页面视为非A4 + } + // 获取第一页高度(粗略判断:大于A5高度即认为是A4) + PDPage firstPage = doc.getPage(0); + float pageHeight = firstPage.getMediaBox().getHeight(); + return pageHeight > A5_HEIGHT; // 核心判断逻辑 + } catch (Exception e) { + // PDF损坏、加载失败等异常,均视为非A4(粗略判断容错) + return false; + } + } + + public static String convertBase64PdfToA5IfConfigured(String base64Pdf, String configuredSize) throws Exception { + if ("A4".equalsIgnoreCase(configuredSize)) { + return base64Pdf; + } + + byte[] pdfBytes = cn.hutool.core.codec.Base64.decode(base64Pdf); + try (PDDocument originalDoc = PDDocument.load(new ByteArrayInputStream(pdfBytes))) { + if (originalDoc.getNumberOfPages() == 0) { + return base64Pdf; // 空文档直接返回 + } + + PDPage firstPage = originalDoc.getPage(0); + PDRectangle mediaBox = firstPage.getMediaBox(); + boolean isA4 = isClose(mediaBox.getWidth(), A4_WIDTH) && isClose(mediaBox.getHeight(), A4_HEIGHT); + + if (isA4) { + return cropA4ToA5(originalDoc); // 仅A4文档执行裁剪 + } + + return base64Pdf; + } + } + + private static boolean isClose(float a, float b) { + return Math.abs(a - b) <= TOLERANCE; + } + + private static String cropA4ToA5(PDDocument originalDoc) throws Exception { + try (PDDocument newDoc = new PDDocument()) { + for (int i = 0; i < originalDoc.getNumberOfPages(); i++) { + cropPage(originalDoc, newDoc, i); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + newDoc.save(baos); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } + } + + // 最终终极适配:2.0.29两参数importPageAsForm + 平移 + 双框同步,无空白、不切顶 + private static void cropPage(PDDocument sourceDoc, PDDocument targetDoc, int pageIndex) throws Exception { + PDPage sourcePage = sourceDoc.getPage(pageIndex); + PDRectangle sourceMediaBox = sourcePage.getMediaBox(); + float targetWidth = sourceMediaBox.getWidth(); // 保留A4原宽度 + float targetHeight = A5_HEIGHT; // A5高度 + float yOffset = -(A4_HEIGHT - targetHeight); // 向下平移距离(关键:让上半部分落入可视区) + + // 1. 新建A5页面:同步设置mediaBox(物理尺寸)和cropBox(可视区),避免空白 + PDPage targetPage = new PDPage(); + PDRectangle targetBox = new PDRectangle(0f, 0f, targetWidth, targetHeight); + targetPage.setMediaBox(targetBox); + targetPage.setCropBox(targetBox); + targetDoc.addPage(targetPage); + + // 2. 2.0.29兼容:仅用两参数导入整个原页面 + LayerUtility layerUtil = new LayerUtility(targetDoc); + PDFormXObject form = layerUtil.importPageAsForm(sourceDoc, pageIndex); // 仅两个参数,2.0.29支持 + + // 3. 平移绘制:让原页面上半部分显示在新页面中 + try (PDPageContentStream contentStream = new PDPageContentStream(targetDoc, targetPage)) { + // cm指令:向下平移247pt(A4_HEIGHT - A5_HEIGHT),原页面上半部分(247~842pt)对应新页面(0~595pt) + contentStream.appendRawCommands(String.format("1 0 0 1 0 %.2f cm\n", yOffset)); + contentStream.drawForm(form); + } + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9662477..206eccd 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,7 @@ 2.1.7 1.5-beta1 7.2.5 + 2.0.29 9.0.112 @@ -358,6 +359,13 @@ ${itextpdf.version} + + org.apache.pdfbox + pdfbox + ${pdfbox.version} + + + diff --git a/zybgcx/src/main/java/com/czlis/zybgcx/service/impl/ZybgcxServcieImpl.java b/zybgcx/src/main/java/com/czlis/zybgcx/service/impl/ZybgcxServcieImpl.java index 074f189..b5d33d1 100644 --- a/zybgcx/src/main/java/com/czlis/zybgcx/service/impl/ZybgcxServcieImpl.java +++ b/zybgcx/src/main/java/com/czlis/zybgcx/service/impl/ZybgcxServcieImpl.java @@ -1,20 +1,17 @@ package com.czlis.zybgcx.service.impl; import cn.hutool.core.codec.Base64; -import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import com.czlis.common.config.RuoYiConfig; import com.czlis.common.core.domain.Result; import com.czlis.common.core.domain.entity.lis.LabPat; import com.czlis.common.core.domain.entity.lis.LabReqreportPdffile; import com.czlis.common.utils.file.FileUtils; -import com.czlis.common.utils.ip.IpUtils; import com.czlis.common.utils.uuid.UUID; import com.czlis.interfaceCommon.utils.CommonUtil; import com.czlis.interfaceCommon.utils.LisUtil; +import com.czlis.interfaceCommon.utils.PdfPaperConverter; import com.czlis.interfaceCommon.utils.ReportUtil; import com.czlis.zybgcx.mapper.ZybgcxMapper; import com.czlis.zybgcx.pojo.Web_fs_printReport; @@ -24,13 +21,10 @@ import com.czlis.zybgcx.pojo.Web_result; import com.czlis.zybgcx.service.ZybgcxService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.CrossOrigin; -import javax.print.PrintException; + import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @@ -106,6 +100,20 @@ public class ZybgcxServcieImpl implements ZybgcxService { //过滤A5格式报告单 List> collectA5 = bgdhBase64List.stream().filter(bgdhBase64 -> bgdhBase64.get("pageType").equals("A5")).collect(Collectors.toList()); + //其中有可能格式虽然是A5,实际尺寸是A4,需要进行处理 + for (Map stringObjectMap : collectA5) { + String bas64Str = stringObjectMap.get("data").toString(); + if(!PdfPaperConverter.isBase64PdfA4(bas64Str)) continue; + try { + String base64_A5 = PdfPaperConverter.convertBase64PdfToA5IfConfigured(bas64Str, "A5"); + stringObjectMap.put("data", base64_A5); + } catch (Exception e) { + log.error("裁剪pdf出错:",e); + return new Result("0","裁剪pdf出错!"+e.getMessage()); + } + } + + log.info("collectA5:"+collectA5); //对A5格式的报告单进行排序 collectA5.sort(new Comparator>() {