From de4144a1a46ddbcb85494550907ec99fc060acbf Mon Sep 17 00:00:00 2001
From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
Date: Sat, 14 Sep 2024 16:29:39 +0100
Subject: [PATCH] Metadata handling for all PDF endpoints (#1894)
* Add image support to multi-tool page
Related to #278
* changes to support image types
* final touches
* final touches
* final touches
Signed-off-by: a
* final touches
Signed-off-by: a
* final touches
Signed-off-by: a
* final touches
Signed-off-by: a
* final touches
Signed-off-by: a
* final touches
Signed-off-by: a
* final touches
Signed-off-by: a
* Update translation files (#1888)
Signed-off-by: GitHub Action
Co-authored-by: GitHub Action
* final touches
Signed-off-by: a
---------
Signed-off-by: a
Signed-off-by: GitHub Action
Co-authored-by: a
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action
---
.../SPDF/config/PdfMetadataService.java | 80 +++-------
.../SPDF/controller/api/CropController.java | 12 +-
.../SPDF/controller/api/MergeController.java | 11 +-
.../api/MultiPageLayoutController.java | 12 +-
.../api/PdfImageRemovalController.java | 26 +--
.../controller/api/PdfOverlayController.java | 11 +-
.../api/RearrangePagesPDFController.java | 11 +-
.../controller/api/RotationController.java | 12 +-
.../controller/api/ScalePagesController.java | 12 +-
.../controller/api/SplitPDFController.java | 17 +-
.../api/SplitPdfByChaptersController.java | 12 +-
.../api/SplitPdfBySectionsController.java | 11 +-
.../api/SplitPdfBySizeController.java | 17 +-
.../api/ToSinglePageController.java | 12 +-
.../ConvertBookToPDFController.java | 26 +--
.../api/converters/ConvertHtmlToPDF.java | 13 +-
.../converters/ConvertImgPDFController.java | 12 +-
.../api/converters/ConvertMarkdownToPdf.java | 13 +-
.../converters/ConvertOfficeController.java | 35 +++--
.../ConvertPDFToBookController.java | 13 +-
.../api/converters/ConvertPDFToPDFA.java | 38 +++--
.../api/converters/ConvertWebsiteToPDF.java | 43 +++--
...troller.java => ExtractCSVController.java} | 4 +-
.../api/misc/AutoSplitPdfController.java | 148 +++++++++++-------
.../api/misc/BlankPageController.java | 11 +-
.../api/misc/CompressController.java | 16 +-
.../api/misc/FlattenController.java | 16 +-
.../controller/api/misc/OCRController.java | 19 ++-
.../api/misc/OverlayImageController.java | 13 +-
.../api/misc/PageNumbersController.java | 12 +-
.../controller/api/misc/RepairController.java | 11 +-
.../controller/api/misc/StampController.java | 12 +-
.../api/security/CertSignController.java | 15 +-
.../api/security/PasswordController.java | 15 +-
.../api/security/RedactController.java | 13 +-
.../security/RemoveCertSignController.java | 28 ++--
.../api/security/SanitizeController.java | 12 +-
.../api/security/WatermarkController.java | 12 +-
.../SPDF/service/CustomPDDocumentFactory.java | 100 ++++++++++++
.../software/SPDF/utils/PdfUtils.java | 19 ++-
src/main/resources/messages_it_IT.properties | 8 +-
.../api/RearrangePagesPDFControllerTest.java | 24 ++-
.../converters/ConvertWebsiteToPdfTest.java | 23 ++-
43 files changed, 696 insertions(+), 284 deletions(-)
rename src/main/java/stirling/software/SPDF/controller/api/converters/{ExtractController.java => ExtractCSVController.java} (98%)
create mode 100644 src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java
diff --git a/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java b/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java
index 9eba472e..7b40a878 100644
--- a/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java
+++ b/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java
@@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
-import jakarta.annotation.PostConstruct;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.PdfMetadata;
@@ -15,8 +14,6 @@ import stirling.software.SPDF.model.PdfMetadata;
@Service
public class PdfMetadataService {
- private static PdfMetadataService instance;
-
private final ApplicationProperties applicationProperties;
private final String appVersion;
private final UserServiceInterface userService;
@@ -31,33 +28,7 @@ public class PdfMetadataService {
this.userService = userService;
}
- @PostConstruct
- public void init() {
- instance = this;
- }
-
- // Static methods for easy access
-
- public static PdfMetadata extractMetadataFromPdf(PDDocument pdf) {
- return instance.extractMetadataFromPdfInstance(pdf);
- }
-
- public static void setDefaultMetadata(PDDocument pdf) {
- instance.setDefaultMetadataInstance(pdf);
- }
-
- public static void setMetadataToPdf(PDDocument pdf, PdfMetadata pdfMetadata) {
- instance.setMetadataToPdfInstance(pdf, pdfMetadata);
- }
-
- public static void setMetadataToPdf(
- PDDocument pdf, PdfMetadata pdfMetadata, boolean newlyCreated) {
- instance.setMetadataToPdfInstance(pdf, pdfMetadata, newlyCreated);
- }
-
- // Instance methods
-
- private PdfMetadata extractMetadataFromPdfInstance(PDDocument pdf) {
+ public PdfMetadata extractMetadataFromPdf(PDDocument pdf) {
return PdfMetadata.builder()
.author(pdf.getDocumentInformation().getAuthor())
.producer(pdf.getDocumentInformation().getProducer())
@@ -70,17 +41,16 @@ public class PdfMetadataService {
.build();
}
- private void setDefaultMetadataInstance(PDDocument pdf) {
- PdfMetadata metadata = extractMetadataFromPdfInstance(pdf);
- setMetadataToPdfInstance(pdf, metadata);
+ public void setDefaultMetadata(PDDocument pdf) {
+ PdfMetadata metadata = extractMetadataFromPdf(pdf);
+ setMetadataToPdf(pdf, metadata);
}
- private void setMetadataToPdfInstance(PDDocument pdf, PdfMetadata pdfMetadata) {
- setMetadataToPdfInstance(pdf, pdfMetadata, true);
+ public void setMetadataToPdf(PDDocument pdf, PdfMetadata pdfMetadata) {
+ setMetadataToPdf(pdf, pdfMetadata, false);
}
- private void setMetadataToPdfInstance(
- PDDocument pdf, PdfMetadata pdfMetadata, boolean newlyCreated) {
+ public void setMetadataToPdf(PDDocument pdf, PdfMetadata pdfMetadata, boolean newlyCreated) {
if (newlyCreated || pdfMetadata.getCreationDate() == null) {
setNewDocumentMetadata(pdf, pdfMetadata);
}
@@ -89,35 +59,35 @@ public class PdfMetadataService {
private void setNewDocumentMetadata(PDDocument pdf, PdfMetadata pdfMetadata) {
- String title = pdfMetadata.getTitle();
String creator = "Stirling-PDF";
-// if (applicationProperties
-// .getEnterpriseEdition()
-// .getCustomMetadata()
-// .isAutoUpdateMetadata()) {
+ // if (applicationProperties
+ // .getEnterpriseEdition()
+ // .getCustomMetadata()
+ // .isAutoUpdateMetadata()) {
- // producer =
- //
- // applicationProperties.getEnterpriseEdition().getCustomMetadata().getProducer();
- // creator =
- // applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator();
- // title = applicationProperties.getEnterpriseEdition().getCustomMetadata().getTitle();
+ // producer =
+ //
+ // applicationProperties.getEnterpriseEdition().getCustomMetadata().getProducer();
+ // creator =
+ // applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator();
+ // title = applicationProperties.getEnterpriseEdition().getCustomMetadata().getTitle();
-// if ("{filename}".equals(title)) {
-// title = "Filename"; // Replace with actual filename logic
-// } else if ("{unchanged}".equals(title)) {
-// title = pdfMetadata.getTitle(); // Keep the original title
-// }
-// }
+ // if ("{filename}".equals(title)) {
+ // title = "Filename"; // Replace with actual filename logic
+ // } else if ("{unchanged}".equals(title)) {
+ // title = pdfMetadata.getTitle(); // Keep the original title
+ // }
+ // }
- pdf.getDocumentInformation().setTitle(title);
pdf.getDocumentInformation().setCreator(creator + " " + appVersion);
pdf.getDocumentInformation().setCreationDate(Calendar.getInstance());
}
private void setCommonMetadata(PDDocument pdf, PdfMetadata pdfMetadata) {
String producer = "Stirling-PDF";
+ String title = pdfMetadata.getTitle();
+ pdf.getDocumentInformation().setTitle(title);
pdf.getDocumentInformation().setProducer(producer + " " + appVersion);
pdf.getDocumentInformation().setSubject(pdfMetadata.getSubject());
pdf.getDocumentInformation().setKeywords(pdfMetadata.getKeywords());
diff --git a/src/main/java/stirling/software/SPDF/controller/api/CropController.java b/src/main/java/stirling/software/SPDF/controller/api/CropController.java
index 42addb26..551cd72d 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/CropController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/CropController.java
@@ -13,6 +13,7 @@ import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -23,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.general.CropPdfForm;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -32,6 +34,13 @@ public class CropController {
private static final Logger logger = LoggerFactory.getLogger(CropController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public CropController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/crop", consumes = "multipart/form-data")
@Operation(
summary = "Crops a PDF document",
@@ -40,7 +49,8 @@ public class CropController {
public ResponseEntity cropPdf(@ModelAttribute CropPdfForm form) throws IOException {
PDDocument sourceDocument = Loader.loadPDF(form.getFileInput().getBytes());
- PDDocument newDocument = new PDDocument();
+ PDDocument newDocument =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
int totalPages = sourceDocument.getNumberOfPages();
diff --git a/src/main/java/stirling/software/SPDF/controller/api/MergeController.java b/src/main/java/stirling/software/SPDF/controller/api/MergeController.java
index 6bb25650..9a60fcf6 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/MergeController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/MergeController.java
@@ -22,6 +22,7 @@ import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -33,6 +34,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -43,9 +45,16 @@ public class MergeController {
private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public MergeController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
// Merges a list of PDDocument objects into a single PDDocument
public PDDocument mergeDocuments(List documents) throws IOException {
- PDDocument mergedDoc = new PDDocument();
+ PDDocument mergedDoc = pdfDocumentFactory.createNewDocument();
for (PDDocument doc : documents) {
for (PDPage page : doc.getPages()) {
mergedDoc.addPage(page);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java b/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java
index adc5424d..fbfec731 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java
@@ -14,6 +14,7 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -26,6 +27,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.general.MergeMultiplePagesRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -35,6 +37,13 @@ public class MultiPageLayoutController {
private static final Logger logger = LoggerFactory.getLogger(MultiPageLayoutController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public MultiPageLayoutController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
@Operation(
summary = "Merge multiple pages of a PDF document into a single page",
@@ -60,7 +69,8 @@ public class MultiPageLayoutController {
int rows = pagesPerSheet == 2 || pagesPerSheet == 3 ? 1 : (int) Math.sqrt(pagesPerSheet);
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
- PDDocument newDocument = new PDDocument();
+ PDDocument newDocument =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
PDPage newPage = new PDPage(PDRectangle.A4);
newDocument.addPage(newPage);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/PdfImageRemovalController.java b/src/main/java/stirling/software/SPDF/controller/api/PdfImageRemovalController.java
index d56b7d2d..302b00f4 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/PdfImageRemovalController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/PdfImageRemovalController.java
@@ -3,16 +3,15 @@ package stirling.software.SPDF.controller.api;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import stirling.software.SPDF.model.api.PDFFile;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.service.PdfImageRemovalService;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -25,15 +24,21 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class PdfImageRemovalController {
// Service for removing images from PDFs
- @Autowired private PdfImageRemovalService pdfImageRemovalService;
+ private final PdfImageRemovalService pdfImageRemovalService;
+
+ private final CustomPDDocumentFactory pdfDocumentFactory;
/**
* Constructor for dependency injection of PdfImageRemovalService.
*
* @param pdfImageRemovalService The service used for removing images from PDFs.
*/
- public PdfImageRemovalController(PdfImageRemovalService pdfImageRemovalService) {
+ @Autowired
+ public PdfImageRemovalController(
+ PdfImageRemovalService pdfImageRemovalService,
+ CustomPDDocumentFactory pdfDocumentFactory) {
this.pdfImageRemovalService = pdfImageRemovalService;
+ this.pdfDocumentFactory = pdfDocumentFactory;
}
/**
@@ -53,14 +58,8 @@ public class PdfImageRemovalController {
description =
"This endpoint remove images from file to reduce the file size.Input:PDF Output:PDF Type:MISO")
public ResponseEntity removeImages(@ModelAttribute PDFFile file) throws IOException {
-
- MultipartFile pdf = file.getFileInput();
-
- // Convert the MultipartFile to a byte array
- byte[] pdfBytes = pdf.getBytes();
-
- // Load the PDF document from the byte array
- PDDocument document = Loader.loadPDF(pdfBytes);
+ // Load the PDF document
+ PDDocument document = pdfDocumentFactory.load(file);
// Remove images from the PDF document using the service
PDDocument modifiedDocument = pdfImageRemovalService.removeImagesFromPdf(document);
@@ -74,7 +73,8 @@ public class PdfImageRemovalController {
// Generate a new filename for the modified PDF
String mergedFileName =
- pdf.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_images.pdf";
+ file.getFileInput().getOriginalFilename().replaceFirst("[.][^.]+$", "")
+ + "_removed_images.pdf";
// Convert the byte array to a web response and return it
return WebResponseUtils.bytesToWebResponse(outputStream.toByteArray(), mergedFileName);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/PdfOverlayController.java b/src/main/java/stirling/software/SPDF/controller/api/PdfOverlayController.java
index 48c987cf..7ff17ccb 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/PdfOverlayController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/PdfOverlayController.java
@@ -12,6 +12,7 @@ import java.util.Map;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.multipdf.Overlay;
import org.apache.pdfbox.pdmodel.PDDocument;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -25,6 +26,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.general.OverlayPdfsRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -33,6 +35,13 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "General", description = "General APIs")
public class PdfOverlayController {
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public PdfOverlayController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data")
@Operation(
summary = "Overlay PDF files in various modes",
@@ -56,7 +65,7 @@ public class PdfOverlayController {
// "FixedRepeatOverlay"
int[] counts = request.getCounts(); // Used for FixedRepeatOverlay mode
- try (PDDocument basePdf = Loader.loadPDF(baseFile.getBytes());
+ try (PDDocument basePdf = pdfDocumentFactory.load(baseFile);
Overlay overlay = new Overlay()) {
Map overlayGuide =
prepareOverlayGuide(
diff --git a/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java
index 3a9ed47b..8eb08dbf 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java
@@ -10,6 +10,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -24,6 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.SortTypes;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.model.api.general.RearrangePagesRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -34,6 +36,13 @@ public class RearrangePagesPDFController {
private static final Logger logger = LoggerFactory.getLogger(RearrangePagesPDFController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public RearrangePagesPDFController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@Operation(
summary = "Remove pages from a PDF file",
@@ -45,7 +54,7 @@ public class RearrangePagesPDFController {
MultipartFile pdfFile = request.getFileInput();
String pagesToDelete = request.getPageNumbers();
- PDDocument document = Loader.loadPDF(pdfFile.getBytes());
+ PDDocument document = pdfDocumentFactory.load(pdfFile);
// Split the page order string into an array of page numbers or range of numbers
String[] pageOrderArr = pagesToDelete.split(",");
diff --git a/src/main/java/stirling/software/SPDF/controller/api/RotationController.java b/src/main/java/stirling/software/SPDF/controller/api/RotationController.java
index 76f508d3..1c416a07 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/RotationController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/RotationController.java
@@ -2,12 +2,12 @@ package stirling.software.SPDF.controller.api;
import java.io.IOException;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -20,6 +20,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.general.RotatePDFRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -29,6 +30,13 @@ public class RotationController {
private static final Logger logger = LoggerFactory.getLogger(RotationController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public RotationController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
@Operation(
summary = "Rotate a PDF file",
@@ -39,7 +47,7 @@ public class RotationController {
MultipartFile pdfFile = request.getFileInput();
Integer angle = request.getAngle();
// Load the PDF document
- PDDocument document = Loader.loadPDF(pdfFile.getBytes());
+ PDDocument document = pdfDocumentFactory.load(request);
// Get the list of pages in the document
PDPageTree pages = document.getPages();
diff --git a/src/main/java/stirling/software/SPDF/controller/api/ScalePagesController.java b/src/main/java/stirling/software/SPDF/controller/api/ScalePagesController.java
index 5eb1205d..9b7714ad 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/ScalePagesController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/ScalePagesController.java
@@ -15,6 +15,7 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -27,6 +28,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.general.ScalePagesRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -36,6 +38,13 @@ public class ScalePagesController {
private static final Logger logger = LoggerFactory.getLogger(ScalePagesController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public ScalePagesController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data")
@Operation(
summary = "Change the size of a PDF page/document",
@@ -48,7 +57,8 @@ public class ScalePagesController {
float scaleFactor = request.getScaleFactor();
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
- PDDocument outputDocument = new PDDocument();
+ PDDocument outputDocument =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
PDRectangle targetSize = getTargetSize(targetPDRectangle, sourceDocument);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java
index af662433..2da76fa3 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java
@@ -15,6 +15,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -27,9 +28,8 @@ import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
-import stirling.software.SPDF.config.PdfMetadataService;
-import stirling.software.SPDF.model.PdfMetadata;
import stirling.software.SPDF.model.api.PDFWithPageNums;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -38,6 +38,12 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class SplitPDFController {
private static final Logger logger = LoggerFactory.getLogger(SplitPDFController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public SplitPDFController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
@PostMapping(consumes = "multipart/form-data", value = "/split-pages")
@Operation(
@@ -51,7 +57,7 @@ public class SplitPDFController {
// open the pdf document
PDDocument document = Loader.loadPDF(file.getBytes());
- PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document);
+ // PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document);
int totalPages = document.getNumberOfPages();
List pageNumbers = request.getPageNumbersList(document, false);
System.out.println(
@@ -70,7 +76,8 @@ public class SplitPDFController {
List splitDocumentsBoas = new ArrayList<>();
int previousPageNumber = 0;
for (int splitPoint : pageNumbers) {
- try (PDDocument splitDocument = new PDDocument()) {
+ try (PDDocument splitDocument =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(document)) {
for (int i = previousPageNumber; i <= splitPoint; i++) {
PDPage page = document.getPage(i);
splitDocument.addPage(page);
@@ -79,7 +86,7 @@ public class SplitPDFController {
previousPageNumber = splitPoint + 1;
// Transfer metadata to split pdf
- PdfMetadataService.setMetadataToPdf(splitDocument, metadata);
+ // PdfMetadataService.setMetadataToPdf(splitDocument, metadata);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
splitDocument.save(baos);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java
index 8d020b16..9d03f8b6 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java
@@ -15,6 +15,7 @@ import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocume
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -44,6 +45,13 @@ public class SplitPdfByChaptersController {
private static final Logger logger =
LoggerFactory.getLogger(SplitPdfByChaptersController.class);
+ private final PdfMetadataService pdfMetadataService;
+
+ @Autowired
+ public SplitPdfByChaptersController(PdfMetadataService pdfMetadataService) {
+ this.pdfMetadataService = pdfMetadataService;
+ }
+
@PostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data")
@Operation(
summary = "Split PDFs by Chapters",
@@ -258,7 +266,7 @@ public class SplitPdfByChaptersController {
List splitDocumentsBoas = new ArrayList<>();
PdfMetadata metadata = null;
if (includeMetadata) {
- metadata = PdfMetadataService.extractMetadataFromPdf(sourceDocument);
+ metadata = pdfMetadataService.extractMetadataFromPdf(sourceDocument);
}
for (Bookmark bookmark : bookmarks) {
try (PDDocument splitDocument = new PDDocument()) {
@@ -273,7 +281,7 @@ public class SplitPdfByChaptersController {
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (includeMetadata) {
- PdfMetadataService.setMetadataToPdf(splitDocument, metadata);
+ pdfMetadataService.setMetadataToPdf(splitDocument, metadata);
}
splitDocument.save(baos);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java
index ce4a61d4..2b4f1313 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySectionsController.java
@@ -20,6 +20,7 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -33,6 +34,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -43,6 +45,13 @@ public class SplitPdfBySectionsController {
private static final Logger logger =
LoggerFactory.getLogger(SplitPdfBySectionsController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public SplitPdfBySectionsController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
@Operation(
summary = "Split PDF pages into smaller sections",
@@ -65,7 +74,7 @@ public class SplitPdfBySectionsController {
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
if (merge) {
- MergeController mergeController = new MergeController();
+ MergeController mergeController = new MergeController(pdfDocumentFactory);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mergeController.mergeDocuments(splitDocuments).save(baos);
return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), filename + "_split.pdf");
diff --git a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySizeController.java b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySizeController.java
index b3772b3b..6016e532 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySizeController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfBySizeController.java
@@ -12,6 +12,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -25,6 +26,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -34,6 +36,12 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class SplitPdfBySizeController {
private static final Logger logger = LoggerFactory.getLogger(SplitPdfBySizeController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public SplitPdfBySizeController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
@Operation(
@@ -84,7 +92,8 @@ public class SplitPdfBySizeController {
PDDocument sourceDocument, long maxBytes, ZipOutputStream zipOut, String baseFilename)
throws IOException {
long currentSize = 0;
- PDDocument currentDoc = new PDDocument();
+ PDDocument currentDoc =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
int fileIndex = 1;
for (int pageIndex = 0; pageIndex < sourceDocument.getNumberOfPages(); pageIndex++) {
@@ -121,7 +130,8 @@ public class SplitPdfBySizeController {
PDDocument sourceDocument, int pageCount, ZipOutputStream zipOut, String baseFilename)
throws IOException {
int currentPageCount = 0;
- PDDocument currentDoc = new PDDocument();
+ PDDocument currentDoc =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
int fileIndex = 1;
for (PDPage page : sourceDocument.getPages()) {
currentDoc.addPage(page);
@@ -152,7 +162,8 @@ public class SplitPdfBySizeController {
int currentPageIndex = 0;
int fileIndex = 1;
for (int i = 0; i < documentCount; i++) {
- PDDocument currentDoc = new PDDocument();
+ PDDocument currentDoc =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
int pagesToAdd = pagesPerDocument + (i < extraPages ? 1 : 0);
for (int j = 0; j < pagesToAdd; j++) {
diff --git a/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java b/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java
index 30406ec2..9401f3a6 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java
@@ -13,6 +13,7 @@ import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -23,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.PDFFile;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -32,6 +34,13 @@ public class ToSinglePageController {
private static final Logger logger = LoggerFactory.getLogger(ToSinglePageController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public ToSinglePageController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
@Operation(
summary = "Convert a multi-page PDF into a single long page PDF",
@@ -53,7 +62,8 @@ public class ToSinglePageController {
}
// Create new document and page with calculated dimensions
- PDDocument newDocument = new PDDocument();
+ PDDocument newDocument =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
PDPage newPage = new PDPage(new PDRectangle(maxWidth, totalHeight));
newDocument.addPage(newPage);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java
index 41e6520d..694d30ab 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java
@@ -1,30 +1,36 @@
package stirling.software.SPDF.controller.api.converters;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.GeneralFile;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.FileToPdf;
import stirling.software.SPDF.utils.WebResponseUtils;
-@RestController
-@Tag(name = "Convert", description = "Convert APIs")
-@RequestMapping("/api/v1/convert")
+// Disabled for now
+// @RestController
+// @Tag(name = "Convert", description = "Convert APIs")
+// @RequestMapping("/api/v1/convert")
public class ConvertBookToPDFController {
- @Autowired
- @Qualifier("bookAndHtmlFormatsInstalled")
- private boolean bookAndHtmlFormatsInstalled;
+ private final boolean bookAndHtmlFormatsInstalled;
+
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ // @Autowired
+ public ConvertBookToPDFController(
+ CustomPDDocumentFactory pdfDocumentFactory,
+ @Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
+ }
@PostMapping(consumes = "multipart/form-data", value = "/book/pdf")
@Operation(
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java
index c7cfc196..19ba1ac4 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java
@@ -1,28 +1,25 @@
package stirling.software.SPDF.controller.api.converters;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
import stirling.software.SPDF.utils.FileToPdf;
import stirling.software.SPDF.utils.WebResponseUtils;
-@RestController
-@Tag(name = "Convert", description = "Convert APIs")
-@RequestMapping("/api/v1/convert")
+// Disabled for now
+// @RestController
+// @Tag(name = "Convert", description = "Convert APIs")
+// @RequestMapping("/api/v1/convert")
public class ConvertHtmlToPDF {
- @Autowired
+ // @Autowired
@Qualifier("bookAndHtmlFormatsInstalled")
private boolean bookAndHtmlFormatsInstalled;
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java
index e54f1fe4..8cf4246e 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java
@@ -16,6 +16,7 @@ import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.rendering.ImageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -30,6 +31,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.CheckProgramInstall;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
@@ -43,6 +45,13 @@ public class ConvertImgPDFController {
private static final Logger logger = LoggerFactory.getLogger(ConvertImgPDFController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public ConvertImgPDFController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/pdf/img")
@Operation(
summary = "Convert PDF to image(s)",
@@ -178,7 +187,8 @@ public class ConvertImgPDFController {
boolean autoRotate = request.isAutoRotate();
// Convert the file to PDF and get the resulting bytes
- byte[] bytes = PdfUtils.imageToPdf(file, fitOption, autoRotate, colorType);
+ byte[] bytes =
+ PdfUtils.imageToPdf(file, fitOption, autoRotate, colorType, pdfDocumentFactory);
return WebResponseUtils.bytesToWebResponse(
bytes,
file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_converted.pdf");
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java
index 9cefe1ff..5b2f3fdf 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java
@@ -10,29 +10,26 @@ import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.HtmlRenderer;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.GeneralFile;
import stirling.software.SPDF.utils.FileToPdf;
import stirling.software.SPDF.utils.WebResponseUtils;
-@RestController
-@Tag(name = "Convert", description = "Convert APIs")
-@RequestMapping("/api/v1/convert")
+// Disabled for now
+// @RestController
+// @Tag(name = "Convert", description = "Convert APIs")
+// @RequestMapping("/api/v1/convert")
public class ConvertMarkdownToPdf {
- @Autowired
+ // @Autowired
@Qualifier("bookAndHtmlFormatsInstalled")
private boolean bookAndHtmlFormatsInstalled;
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java
index 5e6b3dfd..36e29f27 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java
@@ -1,5 +1,6 @@
package stirling.software.SPDF.controller.api.converters;
+import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -8,6 +9,8 @@ import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FilenameUtils;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -20,6 +23,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.GeneralFile;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -29,7 +33,7 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@RequestMapping("/api/v1/convert")
public class ConvertOfficeController {
- public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
+ public File convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
// Check for valid file extension
String originalFilename = Filenames.toSimpleFileName(inputFile.getOriginalFilename());
if (originalFilename == null
@@ -62,12 +66,10 @@ public class ConvertOfficeController {
.runCommandWithOutputHandling(command);
// Read the converted PDF file
- byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
- return pdfBytes;
+ return tempOutputFile.toFile();
} finally {
// Clean up the temporary files
if (tempInputFile != null) Files.deleteIfExists(tempInputFile);
- Files.deleteIfExists(tempOutputFile);
}
}
@@ -76,6 +78,13 @@ public class ConvertOfficeController {
return fileExtension.matches(extensionPattern);
}
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public ConvertOfficeController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/file/pdf")
@Operation(
summary = "Convert a file to a PDF using LibreOffice",
@@ -86,12 +95,18 @@ public class ConvertOfficeController {
MultipartFile inputFile = request.getFileInput();
// unused but can start server instance if startup time is to long
// LibreOfficeListener.getInstance().start();
+ File file = null;
+ try {
+ file = convertToPdf(inputFile);
- byte[] pdfByteArray = convertToPdf(inputFile);
- return WebResponseUtils.bytesToWebResponse(
- pdfByteArray,
- Filenames.toSimpleFileName(inputFile.getOriginalFilename())
- .replaceFirst("[.][^.]+$", "")
- + "_convertedToPDF.pdf");
+ PDDocument doc = pdfDocumentFactory.load(file);
+ return WebResponseUtils.pdfDocToWebResponse(
+ doc,
+ Filenames.toSimpleFileName(inputFile.getOriginalFilename())
+ .replaceFirst("[.][^.]+$", "")
+ + "_convertedToPDF.pdf");
+ } finally {
+ if (file != null) file.delete();
+ }
}
}
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java
index c8b9dd4d..181b5713 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java
@@ -6,30 +6,27 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.converters.PdfToBookRequest;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.SPDF.utils.WebResponseUtils;
-@RestController
-@Tag(name = "Convert", description = "Convert APIs")
-@RequestMapping("/api/v1/convert")
+// Disabled for now
+// @RestController
+// @Tag(name = "Convert", description = "Convert APIs")
+// @RequestMapping("/api/v1/convert")
public class ConvertPDFToBookController {
- @Autowired
+ // @Autowired
@Qualifier("bookAndHtmlFormatsInstalled")
private boolean bookAndHtmlFormatsInstalled;
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java
index cd748d53..eaaf04bc 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java
@@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
@@ -17,6 +16,7 @@ import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -29,6 +29,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -40,6 +41,13 @@ public class ConvertPDFToPDFA {
private static final Logger logger = LoggerFactory.getLogger(ConvertPDFToPDFA.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public ConvertPDFToPDFA(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@Operation(
summary = "Convert a PDF to a PDF/A",
@@ -54,7 +62,7 @@ public class ConvertPDFToPDFA {
byte[] pdfBytes = inputFile.getBytes();
// Load the PDF document
- PDDocument document = Loader.loadPDF(pdfBytes);
+ PDDocument document = pdfDocumentFactory.load(pdfBytes);
// Get the document catalog
PDDocumentCatalog catalog = document.getDocumentCatalog();
@@ -101,18 +109,18 @@ public class ConvertPDFToPDFA {
ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF)
.runCommandWithOutputHandling(command);
- // Read the optimized PDF file
- byte[] optimizedPdfBytes = Files.readAllBytes(tempOutputFile);
-
- // Clean up the temporary files
- Files.deleteIfExists(tempInputFile);
- Files.deleteIfExists(tempOutputFile);
-
- // Return the optimized PDF as a response
- String outputFilename =
- Filenames.toSimpleFileName(inputFile.getOriginalFilename())
- .replaceFirst("[.][^.]+$", "")
- + "_PDFA.pdf";
- return WebResponseUtils.bytesToWebResponse(optimizedPdfBytes, outputFilename);
+ try {
+ PDDocument doc = pdfDocumentFactory.load(tempOutputFile.toFile());
+ // Return the optimized PDF as a response
+ String outputFilename =
+ Filenames.toSimpleFileName(inputFile.getOriginalFilename())
+ .replaceFirst("[.][^.]+$", "")
+ + "_PDFA.pdf";
+ return WebResponseUtils.pdfDocToWebResponse(doc, outputFilename);
+ } finally {
+ // Clean up the temporary files
+ Files.deleteIfExists(tempInputFile);
+ Files.deleteIfExists(tempOutputFile);
+ }
}
}
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java
index 026690fd..6119bfcf 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java
@@ -6,6 +6,10 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -16,6 +20,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
@@ -26,6 +31,15 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@RequestMapping("/api/v1/convert")
public class ConvertWebsiteToPDF {
+ private static final Logger logger = LoggerFactory.getLogger(ConvertWebsiteToPDF.class);
+
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public ConvertWebsiteToPDF(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@Operation(
summary = "Convert a URL to a PDF",
@@ -46,12 +60,12 @@ public class ConvertWebsiteToPDF {
}
Path tempOutputFile = null;
- byte[] pdfBytes;
+ PDDocument doc = null;
try {
// Prepare the output file path
tempOutputFile = Files.createTempFile("output_", ".pdf");
- // Prepare the OCRmyPDF command
+ // Prepare the WeasyPrint command
List command = new ArrayList<>();
command.add("weasyprint");
command.add(URL);
@@ -61,16 +75,23 @@ public class ConvertWebsiteToPDF {
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
.runCommandWithOutputHandling(command);
- // Read the optimized PDF file
- pdfBytes = Files.readAllBytes(tempOutputFile);
- } finally {
- // Clean up the temporary files
- Files.deleteIfExists(tempOutputFile);
- }
- // Convert URL to a safe filename
- String outputFilename = convertURLToFileName(URL);
+ // Load the PDF using pdfDocumentFactory
+ doc = pdfDocumentFactory.load(tempOutputFile.toFile());
- return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
+ // Convert URL to a safe filename
+ String outputFilename = convertURLToFileName(URL);
+
+ return WebResponseUtils.pdfDocToWebResponse(doc, outputFilename);
+ } finally {
+
+ if (tempOutputFile != null) {
+ try {
+ Files.deleteIfExists(tempOutputFile);
+ } catch (IOException e) {
+ logger.error("Error deleting temporary output file", e);
+ }
+ }
+ }
}
private String convertURLToFileName(String url) {
diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ExtractController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ExtractCSVController.java
similarity index 98%
rename from src/main/java/stirling/software/SPDF/controller/api/converters/ExtractController.java
rename to src/main/java/stirling/software/SPDF/controller/api/converters/ExtractCSVController.java
index 6bd9d8b9..8cf8aa4f 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/converters/ExtractController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ExtractCSVController.java
@@ -30,13 +30,13 @@ import stirling.software.SPDF.model.api.extract.PDFFilePage;
@RestController
@RequestMapping("/api/v1/convert")
@Tag(name = "Convert", description = "Convert APIs")
-public class ExtractController {
+public class ExtractCSVController {
private static final Logger logger = LoggerFactory.getLogger(CropController.class);
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
@Operation(
- summary = "Extracts a PDF document to csv",
+ summary = "Extracts a CSV document from a PDF",
description =
"This operation takes an input PDF file and returns CSV file of whole page. Input:PDF Output:CSV Type:SISO")
public ResponseEntity PdfToCsv(@ModelAttribute PDFFilePage form) throws Exception {
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/AutoSplitPdfController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/AutoSplitPdfController.java
index d57a8bda..88d113ec 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/AutoSplitPdfController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/AutoSplitPdfController.java
@@ -12,11 +12,11 @@ import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -38,6 +38,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -49,6 +50,13 @@ public class AutoSplitPdfController {
private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF";
private static final String QR_CONTENT_OLD = "https://github.com/Frooodle/Stirling-PDF";
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public AutoSplitPdfController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
@Operation(
summary = "Auto split PDF pages into separate documents",
@@ -59,73 +67,93 @@ public class AutoSplitPdfController {
MultipartFile file = request.getFileInput();
boolean duplexMode = request.isDuplexMode();
- PDDocument document = Loader.loadPDF(file.getBytes());
- PDFRenderer pdfRenderer = new PDFRenderer(document);
- pdfRenderer.setSubsamplingAllowed(true);
+ PDDocument document = null;
List splitDocuments = new ArrayList<>();
- List splitDocumentsBoas = new ArrayList<>();
+ Path zipFile = null;
+ byte[] data = null;
- for (int page = 0; page < document.getNumberOfPages(); ++page) {
- BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150);
- String result = decodeQRCode(bim);
- if ((QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result)) && page != 0) {
- splitDocuments.add(new PDDocument());
+ try {
+ document = pdfDocumentFactory.load(file.getInputStream());
+ PDFRenderer pdfRenderer = new PDFRenderer(document);
+ pdfRenderer.setSubsamplingAllowed(true);
+
+ for (int page = 0; page < document.getNumberOfPages(); ++page) {
+ BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150);
+ String result = decodeQRCode(bim);
+ if ((QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result)) && page != 0) {
+ splitDocuments.add(new PDDocument());
+ }
+
+ if (!splitDocuments.isEmpty()
+ && !QR_CONTENT.equals(result)
+ && !QR_CONTENT_OLD.equals(result)) {
+ splitDocuments.get(splitDocuments.size() - 1).addPage(document.getPage(page));
+ } else if (page == 0) {
+ PDDocument firstDocument = new PDDocument();
+ firstDocument.addPage(document.getPage(page));
+ splitDocuments.add(firstDocument);
+ }
+
+ // If duplexMode is true and current page is a divider, then skip next page
+ if (duplexMode && (QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result))) {
+ page++;
+ }
}
- if (!splitDocuments.isEmpty()
- && !QR_CONTENT.equals(result)
- && !QR_CONTENT_OLD.equals(result)) {
- splitDocuments.get(splitDocuments.size() - 1).addPage(document.getPage(page));
- } else if (page == 0) {
- PDDocument firstDocument = new PDDocument();
- firstDocument.addPage(document.getPage(page));
- splitDocuments.add(firstDocument);
+ // Remove split documents that have no pages
+ splitDocuments.removeIf(pdDocument -> pdDocument.getNumberOfPages() == 0);
+
+ zipFile = Files.createTempFile("split_documents", ".zip");
+ String filename =
+ Filenames.toSimpleFileName(file.getOriginalFilename())
+ .replaceFirst("[.][^.]+$", "");
+
+ try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
+ for (int i = 0; i < splitDocuments.size(); i++) {
+ String fileName = filename + "_" + (i + 1) + ".pdf";
+ PDDocument splitDocument = splitDocuments.get(i);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ splitDocument.save(baos);
+ byte[] pdf = baos.toByteArray();
+
+ ZipEntry pdfEntry = new ZipEntry(fileName);
+ zipOut.putNextEntry(pdfEntry);
+ zipOut.write(pdf);
+ zipOut.closeEntry();
+ }
}
- // If duplexMode is true and current page is a divider, then skip next page
- if (duplexMode && (QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result))) {
- page++;
- }
- }
-
- // Remove split documents that have no pages
- splitDocuments.removeIf(pdDocument -> pdDocument.getNumberOfPages() == 0);
-
- for (PDDocument splitDocument : splitDocuments) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- splitDocument.save(baos);
- splitDocumentsBoas.add(baos);
- splitDocument.close();
- }
-
- document.close();
-
- Path zipFile = Files.createTempFile("split_documents", ".zip");
- String filename =
- Filenames.toSimpleFileName(file.getOriginalFilename())
- .replaceFirst("[.][^.]+$", "");
- byte[] data;
-
- try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
- for (int i = 0; i < splitDocumentsBoas.size(); i++) {
- String fileName = filename + "_" + (i + 1) + ".pdf";
- ByteArrayOutputStream baos = splitDocumentsBoas.get(i);
- byte[] pdf = baos.toByteArray();
-
- ZipEntry pdfEntry = new ZipEntry(fileName);
- zipOut.putNextEntry(pdfEntry);
- zipOut.write(pdf);
- zipOut.closeEntry();
- }
- } catch (Exception e) {
- logger.error("exception", e);
- } finally {
data = Files.readAllBytes(zipFile);
- Files.deleteIfExists(zipFile);
- }
- return WebResponseUtils.bytesToWebResponse(
- data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
+ return WebResponseUtils.bytesToWebResponse(
+ data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
+ } finally {
+ // Clean up resources
+ if (document != null) {
+ try {
+ document.close();
+ } catch (IOException e) {
+ logger.error("Error closing main PDDocument", e);
+ }
+ }
+
+ for (PDDocument splitDoc : splitDocuments) {
+ try {
+ splitDoc.close();
+ } catch (IOException e) {
+ logger.error("Error closing split PDDocument", e);
+ }
+ }
+
+ if (zipFile != null) {
+ try {
+ Files.deleteIfExists(zipFile);
+ } catch (IOException e) {
+ logger.error("Error deleting temporary zip file", e);
+ }
+ }
+ }
}
private static String decodeQRCode(BufferedImage bufferedImage) {
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/BlankPageController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/BlankPageController.java
index 4c050355..bf046d65 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/BlankPageController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/BlankPageController.java
@@ -16,6 +16,7 @@ import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -30,6 +31,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -40,6 +42,13 @@ public class BlankPageController {
private static final Logger logger = LoggerFactory.getLogger(BlankPageController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public BlankPageController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/remove-blanks")
@Operation(
summary = "Remove blank pages from a PDF file",
@@ -124,7 +133,7 @@ public class BlankPageController {
public void createZipEntry(ZipOutputStream zos, List pages, String entryName)
throws IOException {
- try (PDDocument document = new PDDocument()) {
+ try (PDDocument document = pdfDocumentFactory.createNewDocument()) {
for (PDPage page : pages) {
document.addPage(page);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/CompressController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/CompressController.java
index 2240dbed..3f55a4f5 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/CompressController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/CompressController.java
@@ -20,6 +20,7 @@ import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -32,6 +33,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.OptimizePdfRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
@@ -44,6 +46,13 @@ public class CompressController {
private static final Logger logger = LoggerFactory.getLogger(CompressController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public CompressController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
@Operation(
summary = "Optimize PDF file",
@@ -258,7 +267,7 @@ public class CompressController {
}
// Read the optimized PDF file
pdfBytes = Files.readAllBytes(tempOutputFile);
-
+ Path finalFile = tempOutputFile;
// Check if optimized file is larger than the original
if (pdfBytes.length > inputFileSize) {
// Log the occurrence
@@ -266,14 +275,15 @@ public class CompressController {
"Optimized file is larger than the original. Returning the original file instead.");
// Read the original file again
- pdfBytes = Files.readAllBytes(tempInputFile);
+ finalFile = tempInputFile;
}
// Return the optimized PDF as a response
String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_Optimized.pdf";
- return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
+ return WebResponseUtils.pdfDocToWebResponse(
+ pdfDocumentFactory.load(finalFile.toFile()), outputFilename);
} finally {
// Clean up the temporary files
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java
index c180fafa..c99b5f73 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java
@@ -14,6 +14,7 @@ import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -25,9 +26,8 @@ import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
-import stirling.software.SPDF.config.PdfMetadataService;
-import stirling.software.SPDF.model.PdfMetadata;
import stirling.software.SPDF.model.api.misc.FlattenRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -37,6 +37,13 @@ public class FlattenController {
private static final Logger logger = LoggerFactory.getLogger(FlattenController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public FlattenController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/flatten")
@Operation(
summary = "Flatten PDF form fields or full page",
@@ -46,7 +53,6 @@ public class FlattenController {
MultipartFile file = request.getFileInput();
PDDocument document = Loader.loadPDF(file.getBytes());
- PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document);
Boolean flattenOnlyForms = request.getFlattenOnlyForms();
if (Boolean.TRUE.equals(flattenOnlyForms)) {
@@ -60,7 +66,8 @@ public class FlattenController {
// flatten whole page aka convert each page to image and readd it (making text
// unselectable)
PDFRenderer pdfRenderer = new PDFRenderer(document);
- PDDocument newDocument = new PDDocument();
+ PDDocument newDocument =
+ pdfDocumentFactory.createNewDocumentBasedOnOldDocument(document);
int numPages = document.getNumberOfPages();
for (int i = 0; i < numPages; i++) {
try {
@@ -80,7 +87,6 @@ public class FlattenController {
logger.error("exception", e);
}
}
- PdfMetadataService.setMetadataToPdf(newDocument, metadata);
return WebResponseUtils.pdfDocToWebResponse(
newDocument, Filenames.toSimpleFileName(file.getOriginalFilename()));
}
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/OCRController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/OCRController.java
index f3ccabf4..96cabb60 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/OCRController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/OCRController.java
@@ -1,5 +1,6 @@
package stirling.software.SPDF.controller.api.misc;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -28,6 +29,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.api.misc.ProcessPdfWithOcrRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -52,6 +54,13 @@ public class OCRController {
.collect(Collectors.toList());
}
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public OCRController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
@Operation(
summary = "Process a PDF file with OCR",
@@ -175,7 +184,7 @@ public class OCRController {
tempOutputFile = tempPdfWithoutImages;
}
// Read the OCR processed PDF file
- byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
+ byte[] pdfBytes = pdfDocumentFactory.loadToBytes(tempOutputFile.toFile());
// Return the OCR processed PDF as a response
String outputFilename =
@@ -196,7 +205,13 @@ public class OCRController {
// Add PDF file to the zip
ZipEntry pdfEntry = new ZipEntry(outputFilename);
zipOut.putNextEntry(pdfEntry);
- Files.copy(tempOutputFile, zipOut);
+ try (ByteArrayInputStream pdfInputStream = new ByteArrayInputStream(pdfBytes)) {
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = pdfInputStream.read(buffer)) != -1) {
+ zipOut.write(buffer, 0, length);
+ }
+ }
zipOut.closeEntry();
// Add text file to the zip
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/OverlayImageController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/OverlayImageController.java
index c3fad457..893fc1e5 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/OverlayImageController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/OverlayImageController.java
@@ -4,6 +4,7 @@ import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -17,6 +18,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.OverlayImageRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -27,6 +29,13 @@ public class OverlayImageController {
private static final Logger logger = LoggerFactory.getLogger(OverlayImageController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public OverlayImageController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/add-image")
@Operation(
summary = "Overlay image onto a PDF file",
@@ -41,7 +50,9 @@ public class OverlayImageController {
try {
byte[] pdfBytes = pdfFile.getBytes();
byte[] imageBytes = imageFile.getBytes();
- byte[] result = PdfUtils.overlayImage(pdfBytes, imageBytes, x, y, everyPage);
+ byte[] result =
+ PdfUtils.overlayImage(
+ pdfDocumentFactory, pdfBytes, imageBytes, x, y, everyPage);
return WebResponseUtils.bytesToWebResponse(
result,
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/PageNumbersController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/PageNumbersController.java
index ba31dc83..e42998d1 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/PageNumbersController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/PageNumbersController.java
@@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -13,6 +12,7 @@ import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.AddPageNumbersRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -36,6 +37,13 @@ public class PageNumbersController {
private static final Logger logger = LoggerFactory.getLogger(PageNumbersController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public PageNumbersController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/add-page-numbers", consumes = "multipart/form-data")
@Operation(
summary = "Add page numbers to a PDF document",
@@ -52,7 +60,7 @@ public class PageNumbersController {
String customText = request.getCustomText();
int pageNumber = startingNumber;
byte[] fileBytes = file.getBytes();
- PDDocument document = Loader.loadPDF(fileBytes);
+ PDDocument document = pdfDocumentFactory.load(fileBytes);
float font_size = request.getFontSize();
String font_type = request.getFontType();
float marginFactor;
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/RepairController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/RepairController.java
index 06c652a2..be0827cc 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/RepairController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/RepairController.java
@@ -8,6 +8,7 @@ import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -20,6 +21,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.PDFFile;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -31,6 +33,13 @@ public class RepairController {
private static final Logger logger = LoggerFactory.getLogger(RepairController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public RepairController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/repair")
@Operation(
summary = "Repair a PDF file",
@@ -58,7 +67,7 @@ public class RepairController {
.runCommandWithOutputHandling(command);
// Read the optimized PDF file
- pdfBytes = Files.readAllBytes(tempOutputFile);
+ pdfBytes = pdfDocumentFactory.loadToBytes(tempOutputFile.toFile());
// Return the optimized PDF as a response
String outputFilename =
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java
index ecf41557..b15b76e7 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java
@@ -12,7 +12,6 @@ import java.util.List;
import javax.imageio.ImageIO;
import org.apache.commons.io.IOUtils;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -25,6 +24,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -38,6 +38,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.AddStampRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -45,6 +46,13 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Misc", description = "Miscellaneous APIs")
public class StampController {
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public StampController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/add-stamp")
@Operation(
summary = "Add stamp to a PDF file",
@@ -86,7 +94,7 @@ public class StampController {
}
// Load the input PDF
- PDDocument document = Loader.loadPDF(pdfFile.getBytes());
+ PDDocument document = pdfDocumentFactory.load(pdfFile);
List pageNumbers = request.getPageNumbersList(document, true);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java
index 6ff75ebd..c37fcc9c 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java
@@ -16,7 +16,6 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Calendar;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.examples.signature.CreateSignatureBase;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
@@ -35,6 +34,7 @@ import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -47,6 +47,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.security.SignPDFWithCertRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -71,6 +72,13 @@ public class CertSignController {
}
}
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public CertSignController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/cert-sign")
@Operation(
summary = "Sign PDF with a Digital Certificate",
@@ -122,7 +130,7 @@ public class CertSignController {
CreateSignature createSignature = new CreateSignature(ks, password.toCharArray());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- sign(pdf.getBytes(), baos, createSignature, name, location, reason);
+ sign(pdfDocumentFactory, pdf.getBytes(), baos, createSignature, name, location, reason);
return WebResponseUtils.boasToWebResponse(
baos,
Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
@@ -130,13 +138,14 @@ public class CertSignController {
}
private static void sign(
+ CustomPDDocumentFactory pdfDocumentFactory,
byte[] input,
OutputStream output,
CreateSignature instance,
String name,
String location,
String reason) {
- try (PDDocument doc = Loader.loadPDF(input)) {
+ try (PDDocument doc = pdfDocumentFactory.load(input)) {
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java b/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java
index 84c44933..d738ae79 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java
@@ -2,12 +2,12 @@ package stirling.software.SPDF.controller.api.security;
import java.io.IOException;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.security.AddPasswordRequest;
import stirling.software.SPDF.model.api.security.PDFPasswordRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -30,6 +31,13 @@ public class PasswordController {
private static final Logger logger = LoggerFactory.getLogger(PasswordController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public PasswordController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/remove-password")
@Operation(
summary = "Remove password from a PDF file",
@@ -39,8 +47,7 @@ public class PasswordController {
throws IOException {
MultipartFile fileInput = request.getFileInput();
String password = request.getPassword();
-
- PDDocument document = Loader.loadPDF(fileInput.getBytes(), password);
+ PDDocument document = pdfDocumentFactory.load(fileInput, password);
document.setAllSecurityToBeRemoved(true);
return WebResponseUtils.pdfDocToWebResponse(
document,
@@ -69,7 +76,7 @@ public class PasswordController {
boolean canPrint = request.isCanPrint();
boolean canPrintFaithful = request.isCanPrintFaithful();
- PDDocument document = Loader.loadPDF(fileInput.getBytes());
+ PDDocument document = pdfDocumentFactory.load(fileInput);
AccessPermission ap = new AccessPermission();
ap.setCanAssembleDocument(!canAssembleDocument);
ap.setCanExtractContent(!canExtractContent);
diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java
index b3eec2b1..40dc2c75 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java
@@ -5,12 +5,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.PDFText;
import stirling.software.SPDF.model.api.security.RedactPdfRequest;
import stirling.software.SPDF.pdf.TextFinder;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -35,6 +36,13 @@ public class RedactController {
private static final Logger logger = LoggerFactory.getLogger(RedactController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public RedactController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(value = "/auto-redact", consumes = "multipart/form-data")
@Operation(
summary = "Redacts listOfText in a PDF document",
@@ -52,8 +60,7 @@ public class RedactController {
System.out.println(listOfTextString);
String[] listOfText = listOfTextString.split("\n");
- byte[] bytes = file.getBytes();
- PDDocument document = Loader.loadPDF(bytes);
+ PDDocument document = pdfDocumentFactory.load(file);
Color redactColor;
try {
diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/RemoveCertSignController.java b/src/main/java/stirling/software/SPDF/controller/api/security/RemoveCertSignController.java
index 6a131a98..bd4c8c3d 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/security/RemoveCertSignController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/security/RemoveCertSignController.java
@@ -1,10 +1,8 @@
package stirling.software.SPDF.controller.api.security;
-import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.stream.Collectors;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
@@ -12,6 +10,7 @@ import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -24,6 +23,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.PDFFile;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -33,6 +33,13 @@ public class RemoveCertSignController {
private static final Logger logger = LoggerFactory.getLogger(RemoveCertSignController.class);
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public RemoveCertSignController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/remove-cert-sign")
@Operation(
summary = "Remove digital signature from PDF",
@@ -42,14 +49,8 @@ public class RemoveCertSignController {
throws Exception {
MultipartFile pdf = request.getFileInput();
- // Convert MultipartFile to byte[]
- byte[] pdfBytes = pdf.getBytes();
-
- // Create a ByteArrayOutputStream to hold the resulting PDF
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
// Load the PDF document
- PDDocument document = Loader.loadPDF(pdfBytes);
+ PDDocument document = pdfDocumentFactory.load(pdf);
// Get the document catalog
PDDocumentCatalog catalog = document.getDocumentCatalog();
@@ -67,14 +68,9 @@ public class RemoveCertSignController {
acroForm.flatten(fieldsToRemove, false);
}
}
-
- // Save the modified document to the ByteArrayOutputStream
- document.save(baos);
- document.close();
-
// Return the modified PDF as a response
- return WebResponseUtils.boasToWebResponse(
- baos,
+ return WebResponseUtils.pdfDocToWebResponse(
+ document,
Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
+ "_unsigned.pdf");
}
diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/SanitizeController.java b/src/main/java/stirling/software/SPDF/controller/api/security/SanitizeController.java
index dd2c79da..b034d45d 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/security/SanitizeController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/security/SanitizeController.java
@@ -2,7 +2,6 @@ package stirling.software.SPDF.controller.api.security;
import java.io.IOException;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -21,6 +20,7 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -33,6 +33,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.security.SanitizePdfRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@@ -40,6 +41,13 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Security", description = "Security APIs")
public class SanitizeController {
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public SanitizeController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/sanitize-pdf")
@Operation(
summary = "Sanitize a PDF file",
@@ -54,7 +62,7 @@ public class SanitizeController {
boolean removeLinks = request.isRemoveLinks();
boolean removeFonts = request.isRemoveFonts();
- PDDocument document = Loader.loadPDF(inputFile.getBytes());
+ PDDocument document = pdfDocumentFactory.load(inputFile);
if (removeJavaScript) {
sanitizeJavaScript(document);
}
diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java b/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java
index 0b36cd5e..de7efd71 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java
@@ -11,7 +11,6 @@ import java.nio.file.Files;
import javax.imageio.ImageIO;
import org.apache.commons.io.IOUtils;
-import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -23,6 +22,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -36,6 +36,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.security.AddWatermarkRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@@ -44,6 +45,13 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Security", description = "Security APIs")
public class WatermarkController {
+ private final CustomPDDocumentFactory pdfDocumentFactory;
+
+ @Autowired
+ public WatermarkController(CustomPDDocumentFactory pdfDocumentFactory) {
+ this.pdfDocumentFactory = pdfDocumentFactory;
+ }
+
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
@Operation(
summary = "Add watermark to a PDF file",
@@ -64,7 +72,7 @@ public class WatermarkController {
boolean convertPdfToImage = request.isConvertPDFToImage();
// Load the input PDF
- PDDocument document = Loader.loadPDF(pdfFile.getBytes());
+ PDDocument document = pdfDocumentFactory.load(pdfFile);
// Create a page in the document
for (PDPage page : document.getPages()) {
diff --git a/src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java b/src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java
new file mode 100644
index 00000000..b3f9eec7
--- /dev/null
+++ b/src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java
@@ -0,0 +1,100 @@
+package stirling.software.SPDF.service;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.pdfbox.Loader;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import stirling.software.SPDF.config.PdfMetadataService;
+import stirling.software.SPDF.model.PdfMetadata;
+import stirling.software.SPDF.model.api.PDFFile;
+
+@Component
+public class CustomPDDocumentFactory {
+
+ private final PdfMetadataService pdfMetadataService;
+
+ @Autowired
+ public CustomPDDocumentFactory(PdfMetadataService pdfMetadataService) {
+ this.pdfMetadataService = pdfMetadataService;
+ }
+
+ public PDDocument createNewDocument() throws IOException {
+ PDDocument document = new PDDocument();
+ pdfMetadataService.setMetadataToPdf(document, PdfMetadata.builder().build(), true);
+ return document;
+ }
+
+ public PDDocument createNewDocumentBasedOnOldDocument(PDDocument oldDocument)
+ throws IOException {
+ PDDocument document = new PDDocument();
+ pdfMetadataService.setMetadataToPdf(
+ document, pdfMetadataService.extractMetadataFromPdf(oldDocument), true);
+ return document;
+ }
+
+ public byte[] loadToBytes(File file) throws IOException {
+ PDDocument document = load(file);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ document.save(baos);
+ // Close the document
+ document.close();
+ return baos.toByteArray();
+ }
+
+ public byte[] loadToBytes(byte[] bytes) throws IOException {
+ PDDocument document = load(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ document.save(baos);
+ // Close the document
+ document.close();
+ return baos.toByteArray();
+ }
+
+ // if loading from a file, assume the file has been made with Stirling-PDF
+ public PDDocument load(File file) throws IOException {
+ PDDocument document = Loader.loadPDF(file);
+ pdfMetadataService.setMetadataToPdf(document, PdfMetadata.builder().build(), true);
+ return document;
+ }
+
+ public PDDocument load(InputStream input) throws IOException {
+ return load(input.readAllBytes());
+ }
+
+ public PDDocument load(byte[] input) throws IOException {
+ PDDocument document = Loader.loadPDF(input);
+ pdfMetadataService.setDefaultMetadata(document);
+ return document;
+ }
+
+ public PDDocument load(PDFFile pdfFile) throws IOException {
+ return load(pdfFile.getFileInput());
+ }
+
+ public PDDocument load(MultipartFile pdfFile) throws IOException {
+ return load(pdfFile.getBytes());
+ }
+
+ public PDDocument load(String path) throws IOException {
+ return load(new File(path));
+ }
+
+ public PDDocument load(MultipartFile fileInput, String password) throws IOException {
+ return load(fileInput.getBytes(), password);
+ }
+
+ private PDDocument load(byte[] bytes, String password) throws IOException {
+ PDDocument document = Loader.loadPDF(bytes, password);
+ pdfMetadataService.setDefaultMetadata(document);
+ return document;
+ }
+
+ // Add other load methods as needed, following the same pattern
+}
diff --git a/src/main/java/stirling/software/SPDF/utils/PdfUtils.java b/src/main/java/stirling/software/SPDF/utils/PdfUtils.java
index 160e01da..3416dee6 100644
--- a/src/main/java/stirling/software/SPDF/utils/PdfUtils.java
+++ b/src/main/java/stirling/software/SPDF/utils/PdfUtils.java
@@ -36,6 +36,8 @@ import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
+
public class PdfUtils {
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
@@ -380,9 +382,13 @@ public class PdfUtils {
}
public static byte[] imageToPdf(
- MultipartFile[] files, String fitOption, boolean autoRotate, String colorType)
+ MultipartFile[] files,
+ String fitOption,
+ boolean autoRotate,
+ String colorType,
+ CustomPDDocumentFactory pdfDocumentFactory)
throws IOException {
- try (PDDocument doc = new PDDocument()) {
+ try (PDDocument doc = pdfDocumentFactory.createNewDocument()) {
for (MultipartFile file : files) {
String contentType = file.getContentType();
String originalFilename = Filenames.toSimpleFileName(file.getOriginalFilename());
@@ -470,10 +476,15 @@ public class PdfUtils {
}
public static byte[] overlayImage(
- byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage)
+ CustomPDDocumentFactory pdfDocumentFactory,
+ byte[] pdfBytes,
+ byte[] imageBytes,
+ float x,
+ float y,
+ boolean everyPage)
throws IOException {
- PDDocument document = Loader.loadPDF(pdfBytes);
+ PDDocument document = pdfDocumentFactory.load(pdfBytes);
// Get the first page of the PDF
int pages = document.getNumberOfPages();
diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties
index 9798fb34..58505fcd 100644
--- a/src/main/resources/messages_it_IT.properties
+++ b/src/main/resources/messages_it_IT.properties
@@ -77,10 +77,10 @@ color=Colore
sponsor=Sponsor
info=Info
-legal.privacy=Informativa sulla privacy
-legal.terms=Termini e Condizioni
-legal.accessibility=AccessibilitÃ
-legal.cookie=Informativa sui cookie
+legal.privacy=Privacy Policy
+legal.terms=Terms and Conditions
+legal.accessibility=Accessibility
+legal.cookie=Cookie Policy
legal.impressum=Impressum
###############
diff --git a/src/test/java/stirling/software/SPDF/controller/api/RearrangePagesPDFControllerTest.java b/src/test/java/stirling/software/SPDF/controller/api/RearrangePagesPDFControllerTest.java
index 209c7f54..4c91ffae 100644
--- a/src/test/java/stirling/software/SPDF/controller/api/RearrangePagesPDFControllerTest.java
+++ b/src/test/java/stirling/software/SPDF/controller/api/RearrangePagesPDFControllerTest.java
@@ -8,15 +8,33 @@ import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;import org.junit.jupiter.api.BeforeEach;
class RearrangePagesPDFControllerTest {
+ @Mock
+ private CustomPDDocumentFactory mockPdfDocumentFactory;
+
+ private RearrangePagesPDFController sut;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ sut = new RearrangePagesPDFController(mockPdfDocumentFactory);
+ }
+
/**
* Tests the behavior of the oddEvenMerge method when there are no pages in the document.
*/
@Test
void oddEvenMerge_noPages() {
- RearrangePagesPDFController sut = new RearrangePagesPDFController();
int totalNumberOfPages = 0;
List newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
@@ -30,7 +48,6 @@ class RearrangePagesPDFControllerTest {
*/
@Test
void oddEvenMerge_oddTotalPageNumber() {
- RearrangePagesPDFController sut = new RearrangePagesPDFController();
int totalNumberOfPages = 5;
List newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
@@ -44,7 +61,6 @@ class RearrangePagesPDFControllerTest {
*/
@Test
void oddEvenMerge_evenTotalPageNumber() {
- RearrangePagesPDFController sut = new RearrangePagesPDFController();
int totalNumberOfPages = 6;
List newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
@@ -72,8 +88,6 @@ class RearrangePagesPDFControllerTest {
"22,47,23,48,24,49'"
})
void oddEvenMerge_multi_test(int totalNumberOfPages, String expectedPageOrder) {
- RearrangePagesPDFController sut = new RearrangePagesPDFController();
-
List newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
assertNotNull(newPageOrder, "Returning null instead of page order list");
diff --git a/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPdfTest.java b/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPdfTest.java
index 0e63b99f..ecf814b0 100644
--- a/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPdfTest.java
+++ b/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPdfTest.java
@@ -1,18 +1,36 @@
package stirling.software.SPDF.controller.api.converters;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.springframework.http.ResponseEntity;
+import stirling.software.SPDF.controller.api.RearrangePagesPDFController;
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
+import stirling.software.SPDF.service.CustomPDDocumentFactory;
+
import static org.junit.jupiter.api.Assertions.*;
public class ConvertWebsiteToPdfTest {
+
+
+ @Mock
+ private CustomPDDocumentFactory mockPdfDocumentFactory;
+
+ private ConvertWebsiteToPDF convertWebsiteToPDF;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ convertWebsiteToPDF = new ConvertWebsiteToPDF(mockPdfDocumentFactory);
+ }
+
@Test
public void test_exemption_is_thrown_when_invalid_url_format_provided() {
String invalid_format_Url = "invalid-url";
- // Arrange
- ConvertWebsiteToPDF convertWebsiteToPDF = new ConvertWebsiteToPDF();
+
UrlToPdfRequest request = new UrlToPdfRequest();
request.setUrlInput(invalid_format_Url);
// Act
@@ -28,7 +46,6 @@ public class ConvertWebsiteToPdfTest {
String unreachable_Url = "https://www.googleeeexyz.com";
// Arrange
- ConvertWebsiteToPDF convertWebsiteToPDF = new ConvertWebsiteToPDF();
UrlToPdfRequest request = new UrlToPdfRequest();
request.setUrlInput(unreachable_Url);
// Act