diff --git a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java index 683c0480..b506029b 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java @@ -24,10 +24,14 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.apache.ibatis.session.SqlSession; +import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.*; import org.apache.shiro.SecurityUtils; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTOneCellAnchor; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; @@ -49,6 +53,11 @@ import java.util.stream.Collectors; @Slf4j public class CoDelExcelTXServiceImpl implements CoDelExcelTXService { + /** + * 公章通常位于模板较下方区域,这里按锚点起始行做筛选删除。 + */ + private static final int SEAL_ANCHOR_MIN_ROW = 10; + @Autowired private CoDelMapper coDelMapper; @Autowired @@ -1946,6 +1955,7 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService { if (onlyInvoicePackingPdf) { retainFirstSheets(excelWorkbook, 2); + removeInvoicePackingSealPictures(excelWorkbook); } compactLoadingNoRowIfNeeded(excelWorkbook); // 将Excel转换为PDF @@ -1984,6 +1994,62 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService { } } + /** + * 仅导出发票/箱单PDF时,移除前两页下方区域的图片公章。 + */ + private void removeInvoicePackingSealPictures(XSSFWorkbook workbook) { + if (workbook == null) { + return; + } + int targetSheetCount = Math.min(2, workbook.getNumberOfSheets()); + for (int i = 0; i < targetSheetCount; i++) { + XSSFSheet sheet = workbook.getSheetAt(i); + if (sheet == null) { + continue; + } + removeSealPicturesFromSheet(sheet); + } + } + + /** + * 删除sheet中锚点起始行大于阈值的图片(主要用于移除公章)。 + */ + private void removeSealPicturesFromSheet(XSSFSheet sheet) { + for (POIXMLDocumentPart relation : sheet.getRelations()) { + if (!(relation instanceof XSSFDrawing)) { + continue; + } + XSSFDrawing drawing = (XSSFDrawing) relation; + CTDrawing ctDrawing = drawing.getCTDrawing(); + removeSealPicturesFromTwoCellAnchors(ctDrawing); + removeSealPicturesFromOneCellAnchors(ctDrawing); + } + } + + private void removeSealPicturesFromTwoCellAnchors(CTDrawing ctDrawing) { + for (int i = ctDrawing.sizeOfTwoCellAnchorArray() - 1; i >= 0; i--) { + CTTwoCellAnchor anchor = ctDrawing.getTwoCellAnchorArray(i); + if (anchor != null + && anchor.isSetPic() + && anchor.getFrom() != null + && anchor.getFrom().getRow() > SEAL_ANCHOR_MIN_ROW) { + ctDrawing.removeTwoCellAnchor(i); + } + } + } + + private void removeSealPicturesFromOneCellAnchors(CTDrawing ctDrawing) { + for (int i = ctDrawing.sizeOfOneCellAnchorArray() - 1; i >= 0; i--) { + CTOneCellAnchor anchor = ctDrawing.getOneCellAnchorArray(i); + if (anchor != null + && anchor.isSetPic() + && anchor.getFrom() != null + && anchor.getFrom().getRow() > SEAL_ANCHOR_MIN_ROW) { + ctDrawing.removeOneCellAnchor(i); + } + } + } + /** * 将Excel工作簿转换为PDF字节数组 */