2023-12-11 23:20:31 +00:00
package stirling.software.SPDF.controller.api ;
2023-12-16 19:30:47 +00:00
import java.io.ByteArrayOutputStream ;
import java.io.File ;
import java.io.IOException ;
import java.util.HashMap ;
import java.util.Map ;
2023-12-11 23:20:31 +00:00
import org.apache.pdfbox.multipdf.Overlay ;
import org.apache.pdfbox.pdmodel.PDDocument ;
2023-12-16 19:30:47 +00:00
import org.springframework.http.MediaType ;
import org.springframework.http.ResponseEntity ;
import org.springframework.web.bind.annotation.ModelAttribute ;
2023-12-11 23:20:31 +00:00
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 ;
2023-12-16 19:30:47 +00:00
2023-12-11 23:20:31 +00:00
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.utils.GeneralUtils ;
import stirling.software.SPDF.utils.WebResponseUtils ;
@RestController
@RequestMapping ( "/api/v1/general" )
@Tag ( name = "General" , description = "General APIs" )
public class PdfOverlayController {
@PostMapping ( value = "/overlay-pdfs" , consumes = "multipart/form-data" )
@Operation ( summary = "Overlay PDF files in various modes" , description = "Overlay PDF files onto a base PDF with different modes: Sequential, Interleaved, or Fixed Repeat. Input:PDF Output:PDF Type:MIMO" )
public ResponseEntity < byte []> overlayPdfs ( @ModelAttribute OverlayPdfsRequest request ) throws IOException {
MultipartFile baseFile = request . getFileInput ();
int overlayPos = request . getOverlayPosition ();
MultipartFile [] overlayFiles = request . getOverlayFiles ();
File [] overlayPdfFiles = new File [ overlayFiles . length ] ;
try {
for ( int i = 0 ; i < overlayFiles . length ; i ++ ) {
overlayPdfFiles [ i ] = GeneralUtils . multipartToFile ( overlayFiles [ i ] );
}
String mode = request . getOverlayMode (); // "SequentialOverlay", "InterleavedOverlay", "FixedRepeatOverlay"
int [] counts = request . getCounts (); // Used for FixedRepeatOverlay mode
try ( PDDocument basePdf = PDDocument . load ( baseFile . getInputStream ());
Overlay overlay = new Overlay ()) {
Map < Integer , String > overlayGuide = prepareOverlayGuide ( basePdf . getNumberOfPages (), overlayPdfFiles , mode , counts );
overlay . setInputPDF ( basePdf );
if ( overlayPos == 0 ) {
overlay . setOverlayPosition ( Overlay . Position . FOREGROUND );
} else {
overlay . setOverlayPosition ( Overlay . Position . BACKGROUND );
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream ();
overlay . overlay ( overlayGuide ). save ( outputStream );
byte [] data = outputStream . toByteArray ();
return WebResponseUtils . bytesToWebResponse ( data , "overlaid.pdf" , MediaType . APPLICATION_PDF );
}
} finally {
for ( File overlayPdfFile : overlayPdfFiles ) {
if ( overlayPdfFile != null ) overlayPdfFile . delete ();
}
}
}
private Map < Integer , String > prepareOverlayGuide ( int basePageCount , File [] overlayFiles , String mode , int [] counts ) throws IOException {
Map < Integer , String > overlayGuide = new HashMap <> ();
switch ( mode ) {
case "SequentialOverlay" :
sequentialOverlay ( overlayGuide , overlayFiles , basePageCount );
break ;
case "InterleavedOverlay" :
interleavedOverlay ( overlayGuide , overlayFiles , basePageCount );
break ;
case "FixedRepeatOverlay" :
fixedRepeatOverlay ( overlayGuide , overlayFiles , counts , basePageCount );
break ;
default :
throw new IllegalArgumentException ( "Invalid overlay mode" );
}
return overlayGuide ;
}
private void sequentialOverlay ( Map < Integer , String > overlayGuide , File [] overlayFiles , int basePageCount ) throws IOException {
int currentPage = 1 ;
for ( File overlayFile : overlayFiles ) {
try ( PDDocument overlayPdf = PDDocument . load ( overlayFile )) {
for ( int i = 0 ; i < overlayPdf . getNumberOfPages (); i ++ ) {
if ( currentPage > basePageCount ) break ;
overlayGuide . put ( currentPage ++ , overlayFile . getAbsolutePath ());
}
}
}
}
private void interleavedOverlay ( Map < Integer , String > overlayGuide , File [] overlayFiles , int basePageCount ) throws IOException {
for ( int i = 0 ; i < basePageCount ; i ++ ) {
File overlayFile = overlayFiles [ i % overlayFiles . length ] ;
overlayGuide . put ( i + 1 , overlayFile . getAbsolutePath ());
}
}
private void fixedRepeatOverlay ( Map < Integer , String > overlayGuide , File [] overlayFiles , int [] counts , int basePageCount ) throws IOException {
if ( overlayFiles . length != counts . length ) {
throw new IllegalArgumentException ( "Counts array length must match the number of overlay files" );
}
int currentPage = 1 ;
for ( int i = 0 ; i < overlayFiles . length ; i ++ ) {
File overlayFile = overlayFiles [ i ] ;
int repeatCount = counts [ i ] ;
for ( int j = 0 ; j < repeatCount ; j ++ ) {
if ( currentPage > basePageCount ) break ;
overlayGuide . put ( currentPage ++ , overlayFile . getAbsolutePath ());
}
}
}
}
// Additional classes like OverlayPdfsRequest, WebResponseUtils, etc. are assumed to be defined elsewhere.