2023-04-28 23:18:10 +01:00
package stirling.software.SPDF.controller.api ;
2023-12-25 23:27:08 +02:00
import io.swagger.v3.oas.annotations.Operation ;
import io.swagger.v3.oas.annotations.tags.Tag ;
2023-12-25 22:36:08 +02:00
import org.apache.pdfbox.io.MemoryUsageSetting ;
import org.apache.pdfbox.multipdf.PDFMergerUtility ;
2023-04-28 23:18:10 +01:00
import org.apache.pdfbox.pdmodel.PDDocument ;
import org.apache.pdfbox.pdmodel.PDPage ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.http.ResponseEntity ;
2023-09-09 00:25:27 +01:00
import org.springframework.web.bind.annotation.ModelAttribute ;
2023-04-28 23:18:10 +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-04-28 23:18:10 +01:00
import org.springframework.web.bind.annotation.RestController ;
import org.springframework.web.multipart.MultipartFile ;
2023-09-09 00:25:27 +01:00
import stirling.software.SPDF.model.api.general.MergePdfsRequest ;
2023-05-31 20:15:48 +01:00
import stirling.software.SPDF.utils.WebResponseUtils ;
2023-04-28 23:18:10 +01:00
2023-12-25 23:27:08 +02:00
import java.io.ByteArrayInputStream ;
import java.io.ByteArrayOutputStream ;
import java.io.IOException ;
import java.nio.file.Files ;
import java.nio.file.Paths ;
import java.nio.file.attribute.BasicFileAttributes ;
import java.util.Arrays ;
import java.util.Comparator ;
import java.util.List ;
2023-04-28 23:18:10 +01:00
@RestController
2023-09-11 23:19:50 +01:00
@RequestMapping ( "/api/v1/general" )
2023-06-25 09:16:32 +01:00
@Tag ( name = "General" , description = "General APIs" )
2023-04-28 23:18:10 +01:00
public class MergeController {
private static final Logger logger = LoggerFactory . getLogger ( MergeController . class );
2023-12-25 22:36:08 +02:00
private PDDocument mergeDocuments ( List < PDDocument > documents ) throws IOException {
PDDocument mergedDoc = new PDDocument ();
for ( PDDocument doc : documents ) {
for ( PDPage page : doc . getPages ()) {
mergedDoc . addPage ( page );
}
2023-04-28 23:18:10 +01:00
}
2023-12-25 22:36:08 +02:00
return mergedDoc ;
2023-08-17 22:03:36 +01:00
}
2023-04-28 23:18:10 +01:00
2023-12-25 22:36:08 +02:00
private Comparator < MultipartFile > getSortComparator ( String sortType ) {
switch ( sortType ) {
case "byFileName" :
return Comparator . comparing ( MultipartFile :: getOriginalFilename );
case "byDateModified" :
return ( file1 , file2 ) -> {
try {
BasicFileAttributes attr1 = Files . readAttributes ( Paths . get ( file1 . getOriginalFilename ()), BasicFileAttributes . class );
BasicFileAttributes attr2 = Files . readAttributes ( Paths . get ( file2 . getOriginalFilename ()), BasicFileAttributes . class );
return attr1 . lastModifiedTime (). compareTo ( attr2 . lastModifiedTime ());
} catch ( IOException e ) {
return 0 ; // If there's an error, treat them as equal
}
};
case "byDateCreated" :
return ( file1 , file2 ) -> {
try {
BasicFileAttributes attr1 = Files . readAttributes ( Paths . get ( file1 . getOriginalFilename ()), BasicFileAttributes . class );
BasicFileAttributes attr2 = Files . readAttributes ( Paths . get ( file2 . getOriginalFilename ()), BasicFileAttributes . class );
return attr1 . creationTime (). compareTo ( attr2 . creationTime ());
} catch ( IOException e ) {
return 0 ; // If there's an error, treat them as equal
}
};
case "byPDFTitle" :
return ( file1 , file2 ) -> {
try ( PDDocument doc1 = PDDocument . load ( file1 . getInputStream ());
PDDocument doc2 = PDDocument . load ( file2 . getInputStream ())) {
String title1 = doc1 . getDocumentInformation (). getTitle ();
String title2 = doc2 . getDocumentInformation (). getTitle ();
return title1 . compareTo ( title2 );
} catch ( IOException e ) {
return 0 ;
}
};
case "orderProvided" :
default :
return ( file1 , file2 ) -> 0 ; // Default is the order provided
}
2023-04-28 23:18:10 +01:00
}
2023-12-25 22:36:08 +02:00
@PostMapping ( consumes = "multipart/form-data" , value = "/merge-pdfs" )
@Operation ( summary = "Merge multiple PDF files into one" ,
description = "This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided. Input:PDF Output:PDF Type:MISO" )
public ResponseEntity < byte []> mergePdfs ( @ModelAttribute MergePdfsRequest form ) throws IOException {
try {
MultipartFile [] files = form . getFileInput ();
Arrays . sort ( files , getSortComparator ( form . getSortType ()));
2023-04-28 23:18:10 +01:00
2023-12-25 22:36:08 +02:00
PDFMergerUtility mergedDoc = new PDFMergerUtility ();
ByteArrayOutputStream docOutputstream = new ByteArrayOutputStream ();
2023-04-28 23:18:10 +01:00
2023-12-25 22:36:08 +02:00
for ( MultipartFile file : files ) {
mergedDoc . addSource ( new ByteArrayInputStream ( file . getBytes ()));
2023-08-17 22:03:36 +01:00
}
2023-12-25 22:36:08 +02:00
2023-12-25 23:27:08 +02:00
mergedDoc . setDestinationFileName ( files [ 0 ] . getOriginalFilename (). replaceFirst ( "[.][^.]+$" , "" ) + "_merged.pdf" );
2023-12-25 22:36:08 +02:00
mergedDoc . setDestinationStream ( docOutputstream );
mergedDoc . mergeDocuments ( MemoryUsageSetting . setupMainMemoryOnly ());
2023-12-25 23:27:08 +02:00
return WebResponseUtils . bytesToWebResponse ( docOutputstream . toByteArray (), mergedDoc . getDestinationFileName ());
2023-12-25 22:36:08 +02:00
} catch ( Exception ex ) {
logger . error ( "Error in merge pdf process" , ex );
throw ex ;
2023-08-17 22:03:36 +01:00
}
2023-04-28 23:18:10 +01:00
}
2023-08-17 22:03:36 +01:00
}