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
2024-01-12 23:15:27 +00:00
import org.apache.pdfbox.Loader ;
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 ;
2023-08-01 00:03:13 +01:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2024-09-14 16:29:39 +01:00
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 ;
2024-09-14 16:29:39 +01:00
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 static final Logger logger = LoggerFactory . getLogger ( ToSinglePageController . class );
2024-09-14 16:29:39 +01:00
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
2024-01-12 23:15:27 +00:00
PDDocument sourceDocument = Loader . loadPDF ( 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
2024-09-14 16:29:39 +01:00
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
}
}