From 1fc40f16c25cc38fb57fa83cd085e119e9a69833 Mon Sep 17 00:00:00 2001 From: Ping Lin Date: Sun, 3 Aug 2025 23:47:13 +0100 Subject: [PATCH] feat: implement backend support for selective page splitting in Split PDF by Sections --- .../api/SplitPdfBySectionsController.java | 82 ++++++++++++------- .../model/api/SplitPdfBySectionsRequest.java | 6 ++ 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java index c2bbd31b5..7920f6aef 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java @@ -5,7 +5,9 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -33,6 +35,7 @@ import lombok.RequiredArgsConstructor; import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest; import stirling.software.common.service.CustomPDFDocumentFactory; +import stirling.software.common.util.GeneralUtils; import stirling.software.common.util.WebResponseUtils; @RestController @@ -55,13 +58,20 @@ public class SplitPdfBySectionsController { List splitDocumentsBoas = new ArrayList<>(); MultipartFile file = request.getFileInput(); + String pageNumbers = request.getPageNumbers(); PDDocument sourceDocument = pdfDocumentFactory.load(file); + // Split the page order string into an array of page numbers or range of numbers + String[] pageOrderArr = pageNumbers.split(","); + List pageListToSplit = + GeneralUtils.parsePageList(pageOrderArr, sourceDocument.getNumberOfPages(), false); + Set pagesToSplit = new HashSet<>(pageListToSplit); + // Process the PDF based on split parameters int horiz = request.getHorizontalDivisions() + 1; int verti = request.getVerticalDivisions() + 1; boolean merge = Boolean.TRUE.equals(request.getMerge()); - List splitDocuments = splitPdfPages(sourceDocument, verti, horiz); + List splitDocuments = splitPdfPages(sourceDocument, verti, horiz, pagesToSplit); String filename = Filenames.toSimpleFileName(file.getOriginalFilename()) @@ -110,51 +120,61 @@ public class SplitPdfBySectionsController { } public List splitPdfPages( - PDDocument document, int horizontalDivisions, int verticalDivisions) + PDDocument document, int horizontalDivisions, int verticalDivisions, Set pagesToSplit) throws IOException { List splitDocuments = new ArrayList<>(); + int pageIndex = 0; for (PDPage originalPage : document.getPages()) { - PDRectangle originalMediaBox = originalPage.getMediaBox(); - float width = originalMediaBox.getWidth(); - float height = originalMediaBox.getHeight(); - float subPageWidth = width / horizontalDivisions; - float subPageHeight = height / verticalDivisions; + // If current page is not to split, add it to the splitDocuments directly. + if (!pagesToSplit.contains(pageIndex)) { + PDDocument newDoc = pdfDocumentFactory.createNewDocument(); + newDoc.addPage(originalPage); + splitDocuments.add(newDoc); + } else { + // Otherwise, split current page. + PDRectangle originalMediaBox = originalPage.getMediaBox(); + float width = originalMediaBox.getWidth(); + float height = originalMediaBox.getHeight(); + float subPageWidth = width / horizontalDivisions; + float subPageHeight = height / verticalDivisions; - LayerUtility layerUtility = new LayerUtility(document); + LayerUtility layerUtility = new LayerUtility(document); - for (int i = 0; i < horizontalDivisions; i++) { - for (int j = 0; j < verticalDivisions; j++) { - PDDocument subDoc = new PDDocument(); - PDPage subPage = new PDPage(new PDRectangle(subPageWidth, subPageHeight)); - subDoc.addPage(subPage); + for (int i = 0; i < horizontalDivisions; i++) { + for (int j = 0; j < verticalDivisions; j++) { + PDDocument subDoc = new PDDocument(); + PDPage subPage = new PDPage(new PDRectangle(subPageWidth, subPageHeight)); + subDoc.addPage(subPage); - PDFormXObject form = + PDFormXObject form = layerUtility.importPageAsForm( - document, document.getPages().indexOf(originalPage)); + document, document.getPages().indexOf(originalPage)); - try (PDPageContentStream contentStream = - new PDPageContentStream( - subDoc, subPage, AppendMode.APPEND, true, true)) { - // Set clipping area and position - float translateX = -subPageWidth * i; + try (PDPageContentStream contentStream = + new PDPageContentStream( + subDoc, subPage, AppendMode.APPEND, true, true)) { + // Set clipping area and position + float translateX = -subPageWidth * i; - // float translateY = height - subPageHeight * (verticalDivisions - j); - float translateY = -subPageHeight * (verticalDivisions - 1 - j); + // float translateY = height - subPageHeight * (verticalDivisions - j); + float translateY = -subPageHeight * (verticalDivisions - 1 - j); - contentStream.saveGraphicsState(); - contentStream.addRect(0, 0, subPageWidth, subPageHeight); - contentStream.clip(); - contentStream.transform(new Matrix(1, 0, 0, 1, translateX, translateY)); + contentStream.saveGraphicsState(); + contentStream.addRect(0, 0, subPageWidth, subPageHeight); + contentStream.clip(); + contentStream.transform(new Matrix(1, 0, 0, 1, translateX, translateY)); - // Draw the form - contentStream.drawForm(form); - contentStream.restoreGraphicsState(); + // Draw the form + contentStream.drawForm(form); + contentStream.restoreGraphicsState(); + } + + splitDocuments.add(subDoc); } - - splitDocuments.add(subDoc); } } + pageIndex++; } return splitDocuments; diff --git a/app/core/src/main/java/stirling/software/SPDF/model/api/SplitPdfBySectionsRequest.java b/app/core/src/main/java/stirling/software/SPDF/model/api/SplitPdfBySectionsRequest.java index 3a89ab686..2fad48203 100644 --- a/app/core/src/main/java/stirling/software/SPDF/model/api/SplitPdfBySectionsRequest.java +++ b/app/core/src/main/java/stirling/software/SPDF/model/api/SplitPdfBySectionsRequest.java @@ -10,6 +10,12 @@ import stirling.software.common.model.api.PDFFile; @Data @EqualsAndHashCode(callSuper = true) public class SplitPdfBySectionsRequest extends PDFFile { + @Schema( + description = "Pages to be split by section", + defaultValue = "all", + requiredMode = Schema.RequiredMode.REQUIRED) + private String pageNumbers; + @Schema( description = "Number of horizontal divisions for each PDF page", defaultValue = "0",