Stirling-PDF/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

98 lines
4.2 KiB
Java
Raw Normal View History

2023-08-01 00:03:13 +01:00
package stirling.software.SPDF.controller.api;
2023-09-02 00:05:50 +01:00
import java.awt.geom.AffineTransform;
2023-08-01 00:03:13 +01:00
import java.io.ByteArrayOutputStream;
2023-08-27 00:39:22 +01:00
import java.io.IOException;
2023-08-01 00:03:13 +01:00
2023-09-03 01:24:02 +01:00
import org.apache.pdfbox.multipdf.LayerUtility;
2023-09-02 00:05:50 +01:00
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
2023-09-03 01:24:02 +01:00
import org.apache.pdfbox.pdmodel.PDPageContentStream;
2023-09-02 00:05:50 +01:00
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.springframework.beans.factory.annotation.Autowired;
2023-08-01 00:03:13 +01:00
import org.springframework.http.ResponseEntity;
2023-09-09 00:25:27 +01:00
import org.springframework.web.bind.annotation.ModelAttribute;
2023-08-01 00:03:13 +01:00
import org.springframework.web.bind.annotation.PostMapping;
2023-09-11 23:19:50 +01:00
import org.springframework.web.bind.annotation.RequestMapping;
2023-08-01 00:03:13 +01:00
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
2023-12-30 19:11:27 +00:00
2023-09-09 00:25:27 +01:00
import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.SPDF.service.CustomPDDocumentFactory;
2023-08-01 00:03:13 +01:00
import stirling.software.SPDF.utils.WebResponseUtils;
2023-12-30 19:11:27 +00:00
2023-08-01 00:03:13 +01:00
@RestController
2023-09-11 23:19:50 +01:00
@RequestMapping("/api/v1/general")
2023-08-01 00:03:13 +01:00
@Tag(name = "General", description = "General APIs")
public class ToSinglePageController {
private final CustomPDDocumentFactory pdfDocumentFactory;
@Autowired
public ToSinglePageController(CustomPDDocumentFactory pdfDocumentFactory) {
this.pdfDocumentFactory = pdfDocumentFactory;
}
2023-08-01 00:03:13 +01:00
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
@Operation(
summary = "Convert a multi-page PDF into a single long page PDF",
description =
"This endpoint converts a multi-page PDF document into a single paged PDF document. The width of the single page will be same as the input's width, but the height will be the sum of all the pages' heights. Input:PDF Output:PDF Type:SISO")
2023-09-09 00:25:27 +01:00
public ResponseEntity<byte[]> pdfToSinglePage(@ModelAttribute PDFFile request)
2023-09-02 19:12:08 +01:00
throws IOException {
// Load the source document
Memory enhancements and PDF decompress API (#3129) # Description of Changes - PDF split by size to check size of PDF as it splits, avoids issue were a PDFs size is different viewed vs saved due to compression caused by repeated data etc. - Additionally memory enhancements for PDF load to dynamically load in memory vs scratch - PDF Decompress API for PDF testing ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.
2025-03-08 00:03:27 +00:00
PDDocument sourceDocument = pdfDocumentFactory.load(request.getFileInput().getBytes());
2023-09-02 19:12:08 +01:00
// Calculate total height and max width
float totalHeight = 0;
float maxWidth = 0;
for (PDPage page : sourceDocument.getPages()) {
PDRectangle pageSize = page.getMediaBox();
totalHeight += pageSize.getHeight();
maxWidth = Math.max(maxWidth, pageSize.getWidth());
2023-12-30 19:11:27 +00:00
}
2023-09-02 19:12:08 +01:00
// Create new document and page with calculated dimensions
PDDocument newDocument =
pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
2023-09-02 19:12:08 +01:00
PDPage newPage = new PDPage(new PDRectangle(maxWidth, totalHeight));
newDocument.addPage(newPage);
// Initialize the content stream of the new page
PDPageContentStream contentStream = new PDPageContentStream(newDocument, newPage);
contentStream.close();
2023-09-09 00:25:27 +01:00
LayerUtility layerUtility = new LayerUtility(newDocument);
float yOffset = totalHeight;
2023-09-02 19:12:08 +01:00
// For each page, copy its content to the new page at the correct offset
for (PDPage page : sourceDocument.getPages()) {
PDFormXObject form =
layerUtility.importPageAsForm(
sourceDocument, sourceDocument.getPages().indexOf(page));
AffineTransform af =
AffineTransform.getTranslateInstance(
0, yOffset - page.getMediaBox().getHeight());
layerUtility.wrapInSaveRestore(newPage);
String defaultLayerName = "Layer" + sourceDocument.getPages().indexOf(page);
layerUtility.appendFormAsLayer(newPage, form, af, defaultLayerName);
yOffset -= page.getMediaBox().getHeight();
2023-12-30 19:11:27 +00:00
}
2023-09-02 19:12:08 +01:00
ByteArrayOutputStream baos = new ByteArrayOutputStream();
newDocument.save(baos);
newDocument.close();
2023-09-09 00:25:27 +01:00
sourceDocument.close();
2023-09-02 19:12:08 +01:00
byte[] result = baos.toByteArray();
2023-09-09 00:25:27 +01:00
return WebResponseUtils.bytesToWebResponse(
2023-12-30 19:11:27 +00:00
result,
2023-09-09 00:25:27 +01:00
request.getFileInput().getOriginalFilename().replaceFirst("[.][^.]+$", "")
+ "_singlePage.pdf");
2023-08-01 00:03:13 +01:00
}
}