Compare commits

...

2 Commits

Author SHA1 Message Date
jiangs
faf71be5db Merge remote-tracking branch 'lis8.0/master' 2025-11-28 09:09:57 +08:00
jiangs
dd30506fe9 pdf报告A4切割A5 2025-11-28 09:09:49 +08:00
4 changed files with 144 additions and 8 deletions

View File

@ -75,6 +75,12 @@
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</dependency>
</dependencies>

View File

@ -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);
}
}
}

View File

@ -45,6 +45,7 @@
<itext.version>2.1.7</itext.version>
<barbecue.version>1.5-beta1</barbecue.version>
<itextpdf.version>7.2.5</itextpdf.version>
<pdfbox.version>2.0.29</pdfbox.version>
<!-- override dependency version -->
<tomcat.version>9.0.112</tomcat.version>
@ -358,6 +359,13 @@
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version>
</dependency>
</dependencies>

View File

@ -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<Map<String, Object>> collectA5 = bgdhBase64List.stream().filter(bgdhBase64 -> bgdhBase64.get("pageType").equals("A5")).collect(Collectors.toList());
//其中有可能格式虽然是A5,实际尺寸是A4,需要进行处理
for (Map<String, Object> 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<Map<String, Object>>() {