mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-11-01 01:21:18 +01:00 
			
		
		
		
	Merge branch 'main' into dependabot/gradle/org.springframework.boot-spring-boot-starter-web-3.1.0
This commit is contained in:
		
						commit
						602df08df5
					
				@ -65,6 +65,7 @@ public class EndpointConfiguration {
 | 
				
			|||||||
        addEndpointToGroup("PageOps", "pdf-organizer");
 | 
					        addEndpointToGroup("PageOps", "pdf-organizer");
 | 
				
			||||||
        addEndpointToGroup("PageOps", "rotate-pdf");
 | 
					        addEndpointToGroup("PageOps", "rotate-pdf");
 | 
				
			||||||
        addEndpointToGroup("PageOps", "multi-page-layout");
 | 
					        addEndpointToGroup("PageOps", "multi-page-layout");
 | 
				
			||||||
 | 
					        addEndpointToGroup("PageOps", "scale-pages");
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // Adding endpoints to "Convert" group
 | 
					        // Adding endpoints to "Convert" group
 | 
				
			||||||
        addEndpointToGroup("Convert", "pdf-to-img");
 | 
					        addEndpointToGroup("Convert", "pdf-to-img");
 | 
				
			||||||
@ -164,7 +165,7 @@ public class EndpointConfiguration {
 | 
				
			|||||||
        addEndpointToGroup("Java", "change-metadata");
 | 
					        addEndpointToGroup("Java", "change-metadata");
 | 
				
			||||||
        addEndpointToGroup("Java", "cert-sign");
 | 
					        addEndpointToGroup("Java", "cert-sign");
 | 
				
			||||||
        addEndpointToGroup("Java", "multi-page-layout");
 | 
					        addEndpointToGroup("Java", "multi-page-layout");
 | 
				
			||||||
        
 | 
					        addEndpointToGroup("Java", "scale-pages");
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        //Javascript
 | 
					        //Javascript
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class MergeController {
 | 
					public class MergeController {
 | 
				
			||||||
@ -65,7 +65,7 @@ public class MergeController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // Return the merged PDF as a response
 | 
					        // Return the merged PDF as a response
 | 
				
			||||||
        ResponseEntity<byte[]> response = PdfUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
 | 
					        ResponseEntity<byte[]> response = WebResponseUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        for (PDDocument doc : documents) {
 | 
					        for (PDDocument doc : documents) {
 | 
				
			||||||
            // Close the document after processing
 | 
					            // Close the document after processing
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package stirling.software.SPDF.controller.api.other;
 | 
					package stirling.software.SPDF.controller.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.ByteArrayInputStream;
 | 
					import java.io.ByteArrayInputStream;
 | 
				
			||||||
import java.io.ByteArrayOutputStream;
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
@ -6,7 +6,6 @@ import java.io.IOException;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
import org.springframework.http.HttpHeaders;
 | 
					 | 
				
			||||||
import org.springframework.http.ResponseEntity;
 | 
					import org.springframework.http.ResponseEntity;
 | 
				
			||||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
					import org.springframework.web.bind.annotation.PostMapping;
 | 
				
			||||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
					import org.springframework.web.bind.annotation.RequestParam;
 | 
				
			||||||
@ -25,6 +24,7 @@ import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
 | 
				
			|||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class MultiPageLayoutController {
 | 
					public class MultiPageLayoutController {
 | 
				
			||||||
@ -92,9 +92,8 @@ public class MultiPageLayoutController {
 | 
				
			|||||||
		outputPdf.close();
 | 
							outputPdf.close();
 | 
				
			||||||
		byte[] pdfContent = baos.toByteArray();
 | 
							byte[] pdfContent = baos.toByteArray();
 | 
				
			||||||
		pdfDoc.close();
 | 
							pdfDoc.close();
 | 
				
			||||||
		return ResponseEntity.ok()
 | 
							
 | 
				
			||||||
				.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"modifiedDocument.pdf\"")
 | 
							return WebResponseUtils.bytesToWebResponse(pdfContent, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_layoutChanged.pdf");
 | 
				
			||||||
				.body(pdfContent);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -2,6 +2,8 @@ package stirling.software.SPDF.controller.api;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -18,7 +20,6 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class RearrangePagesPDFController {
 | 
					public class RearrangePagesPDFController {
 | 
				
			||||||
@ -48,7 +49,7 @@ public class RearrangePagesPDFController {
 | 
				
			|||||||
            int pageIndex = pagesToRemove.get(i);
 | 
					            int pageIndex = pagesToRemove.get(i);
 | 
				
			||||||
            document.removePage(pageIndex);
 | 
					            document.removePage(pageIndex);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_pages.pdf");
 | 
					        return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_pages.pdf");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -239,7 +240,7 @@ public class RearrangePagesPDFController {
 | 
				
			|||||||
                document.addPage(page);
 | 
					                document.addPage(page);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rearranged.pdf");
 | 
					            return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rearranged.pdf");
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            logger.error("Failed rearranging documents", e);
 | 
					            logger.error("Failed rearranging documents", e);
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class RotationController {
 | 
					public class RotationController {
 | 
				
			||||||
@ -46,7 +46,7 @@ public class RotationController {
 | 
				
			|||||||
            page.setRotation(page.getRotation() + angle);
 | 
					            page.setRotation(page.getRotation() + angle);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf");
 | 
					        return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					package stirling.software.SPDF.controller.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayInputStream;
 | 
				
			||||||
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					import org.springframework.http.HttpHeaders;
 | 
				
			||||||
 | 
					import org.springframework.http.ResponseEntity;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.PostMapping;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RequestParam;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RestController;
 | 
				
			||||||
 | 
					import org.springframework.web.multipart.MultipartFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.geom.PageSize;
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.geom.Rectangle;
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.pdf.PdfDocument;
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.pdf.PdfPage;
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.pdf.PdfReader;
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.pdf.PdfWriter;
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
 | 
				
			||||||
 | 
					import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@RestController
 | 
				
			||||||
 | 
					public class ScalePagesController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final Logger logger = LoggerFactory.getLogger(ScalePagesController.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@PostMapping(value = "/scale-pages", consumes = "multipart/form-data")
 | 
				
			||||||
 | 
						@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file.")
 | 
				
			||||||
 | 
						public ResponseEntity<byte[]> mergeMultiplePagesIntoOne(
 | 
				
			||||||
 | 
								@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
 | 
				
			||||||
 | 
								@Parameter(description = "The scale of pages in the output PDF. Acceptable values are A4.", required = true, schema = @Schema(type = "String", allowableValues = { "A4" })) @RequestParam("pageSize") String targetPageSize,
 | 
				
			||||||
 | 
					            @Parameter(description = "The scale of the content on the pages of the output PDF. Acceptable values are floats.", required = true, schema = @Schema(type = "float")) @RequestParam("scaleFactor") float scaleFactor)
 | 
				
			||||||
 | 
								throws IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!targetPageSize.equals("A4")) {
 | 
				
			||||||
 | 
								throw new IllegalArgumentException("pageSize must be A4");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							byte[] bytes = file.getBytes();
 | 
				
			||||||
 | 
							PdfReader reader = new PdfReader(new ByteArrayInputStream(bytes));
 | 
				
			||||||
 | 
							PdfDocument pdfDoc = new PdfDocument(reader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
				
			||||||
 | 
							PdfWriter writer = new PdfWriter(baos);
 | 
				
			||||||
 | 
							PdfDocument outputPdf = new PdfDocument(writer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							PageSize pageSize = new PageSize(PageSize.A4); // TODO: This (and all other PageSize.A4) need to be dynamically changed in response to targetPageSize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int totalPages = pdfDoc.getNumberOfPages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 1; i <= totalPages; i++) {
 | 
				
			||||||
 | 
								PdfPage page = outputPdf.addNewPage(pageSize);
 | 
				
			||||||
 | 
								PdfCanvas pdfCanvas = new PdfCanvas(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Get the page and calculate scaling factors
 | 
				
			||||||
 | 
								Rectangle rect = pdfDoc.getPage(i).getPageSize();
 | 
				
			||||||
 | 
								float scaleWidth = PageSize.A4.getWidth() / rect.getWidth();
 | 
				
			||||||
 | 
								float scaleHeight = PageSize.A4.getHeight() / rect.getHeight();
 | 
				
			||||||
 | 
								float scale = Math.min(scaleWidth, scaleHeight) * scaleFactor;
 | 
				
			||||||
 | 
					            System.out.println("Scale: " + scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								PdfFormXObject formXObject = pdfDoc.getPage(i).copyAsFormXObject(outputPdf);
 | 
				
			||||||
 | 
								float x = (PageSize.A4.getWidth() - rect.getWidth() * scale) / 2; // Center Page
 | 
				
			||||||
 | 
								float y = (PageSize.A4.getHeight() - rect.getHeight() * scale) / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Save the graphics state, apply the transformations, add the object, and then
 | 
				
			||||||
 | 
								// restore the graphics state
 | 
				
			||||||
 | 
								pdfCanvas.saveState();
 | 
				
			||||||
 | 
								pdfCanvas.concatMatrix(scale, 0, 0, scale, x, y);
 | 
				
			||||||
 | 
								pdfCanvas.addXObject(formXObject, 0, 0);
 | 
				
			||||||
 | 
								pdfCanvas.restoreState();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							outputPdf.close();
 | 
				
			||||||
 | 
							byte[] pdfContent = baos.toByteArray();
 | 
				
			||||||
 | 
							pdfDoc.close();
 | 
				
			||||||
 | 
							return WebResponseUtils.bytesToWebResponse(pdfContent, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_scaled.pdf");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.Operation;
 | 
				
			|||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.PdfUtils;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class ConvertImgPDFController {
 | 
					public class ConvertImgPDFController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -98,7 +99,7 @@ public class ConvertImgPDFController {
 | 
				
			|||||||
                    boolean autoRotate) throws IOException {
 | 
					                    boolean autoRotate) throws IOException {
 | 
				
			||||||
        // Convert the file to PDF and get the resulting bytes
 | 
					        // Convert the file to PDF and get the resulting bytes
 | 
				
			||||||
        byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate, colorType);
 | 
					        byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate, colorType);
 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_coverted.pdf");
 | 
					        return WebResponseUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_coverted.pdf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private String getMediaType(String imageFormat) {
 | 
					    private String getMediaType(String imageFormat) {
 | 
				
			||||||
 | 
				
			|||||||
@ -17,8 +17,8 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
import stirling.software.SPDF.utils.ProcessExecutor;
 | 
					import stirling.software.SPDF.utils.ProcessExecutor;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class ConvertOfficeController {
 | 
					public class ConvertOfficeController {
 | 
				
			||||||
@ -72,7 +72,7 @@ public class ConvertOfficeController {
 | 
				
			|||||||
        // LibreOfficeListener.getInstance().start();
 | 
					        // LibreOfficeListener.getInstance().start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        byte[] pdfByteArray = convertToPdf(inputFile);
 | 
					        byte[] pdfByteArray = convertToPdf(inputFile);
 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(pdfByteArray, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
 | 
					        return WebResponseUtils.bytesToWebResponse(pdfByteArray, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,8 +14,8 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
import stirling.software.SPDF.utils.ProcessExecutor;
 | 
					import stirling.software.SPDF.utils.ProcessExecutor;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class ConvertPDFToPDFA {
 | 
					public class ConvertPDFToPDFA {
 | 
				
			||||||
@ -58,7 +58,7 @@ public class ConvertPDFToPDFA {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Return the optimized PDF as a response
 | 
					        // Return the optimized PDF as a response
 | 
				
			||||||
        String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_PDFA.pdf";
 | 
					        String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_PDFA.pdf";
 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
					        return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -28,9 +28,9 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.ImageFinder;
 | 
					import stirling.software.SPDF.pdf.ImageFinder;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
import stirling.software.SPDF.utils.ProcessExecutor;
 | 
					import stirling.software.SPDF.utils.ProcessExecutor;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class BlankPageController {
 | 
					public class BlankPageController {
 | 
				
			||||||
@ -109,7 +109,7 @@ public class BlankPageController {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return PdfUtils.pdfDocToWebResponse(document, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_blanksRemoved.pdf");
 | 
					            return WebResponseUtils.pdfDocToWebResponse(document, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_blanksRemoved.pdf");
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
 | 
					            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
 | 
				
			||||||
 | 
				
			|||||||
@ -31,8 +31,9 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.GeneralUtils;
 | 
				
			||||||
import stirling.software.SPDF.utils.ProcessExecutor;
 | 
					import stirling.software.SPDF.utils.ProcessExecutor;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class CompressController {
 | 
					public class CompressController {
 | 
				
			||||||
@ -55,7 +56,7 @@ public class CompressController {
 | 
				
			|||||||
        Long expectedOutputSize = 0L;
 | 
					        Long expectedOutputSize = 0L;
 | 
				
			||||||
        boolean autoMode = false;
 | 
					        boolean autoMode = false;
 | 
				
			||||||
        if (expectedOutputSizeString != null && expectedOutputSizeString.length() > 1 ) {
 | 
					        if (expectedOutputSizeString != null && expectedOutputSizeString.length() > 1 ) {
 | 
				
			||||||
            expectedOutputSize = PdfUtils.convertSizeToBytes(expectedOutputSizeString);
 | 
					            expectedOutputSize = GeneralUtils.convertSizeToBytes(expectedOutputSizeString);
 | 
				
			||||||
            autoMode = true;
 | 
					            autoMode = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -224,7 +225,7 @@ public class CompressController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Return the optimized PDF as a response
 | 
					        // Return the optimized PDF as a response
 | 
				
			||||||
        String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_Optimized.pdf";
 | 
					        String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_Optimized.pdf";
 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
					        return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -31,8 +31,8 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
import stirling.software.SPDF.utils.ProcessExecutor;
 | 
					import stirling.software.SPDF.utils.ProcessExecutor;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class ExtractImageScansController {
 | 
					public class ExtractImageScansController {
 | 
				
			||||||
@ -147,11 +147,11 @@ public class ExtractImageScansController {
 | 
				
			|||||||
            // Clean up the temporary zip file
 | 
					            // Clean up the temporary zip file
 | 
				
			||||||
            Files.delete(tempZipFile);
 | 
					            Files.delete(tempZipFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return PdfUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
					            return WebResponseUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // Return the processed image as a response
 | 
					            // Return the processed image as a response
 | 
				
			||||||
            byte[] imageBytes = processedImageBytes.get(0);
 | 
					            byte[] imageBytes = processedImageBytes.get(0);
 | 
				
			||||||
            return PdfUtils.bytesToWebResponse(imageBytes, fileName.replaceFirst("[.][^.]+$", "") + ".png", MediaType.IMAGE_PNG);
 | 
					            return WebResponseUtils.bytesToWebResponse(imageBytes, fileName.replaceFirst("[.][^.]+$", "") + ".png", MediaType.IMAGE_PNG);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class ExtractImagesController {
 | 
					public class ExtractImagesController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -106,7 +106,7 @@ public class ExtractImagesController {
 | 
				
			|||||||
        // Create ByteArrayResource from byte array
 | 
					        // Create ByteArrayResource from byte array
 | 
				
			||||||
        byte[] zipContents = baos.toByteArray();
 | 
					        byte[] zipContents = baos.toByteArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return PdfUtils.boasToWebResponse(baos, filename + "_extracted-images.zip", MediaType.APPLICATION_OCTET_STREAM);
 | 
					        return WebResponseUtils.boasToWebResponse(baos, filename + "_extracted-images.zip", MediaType.APPLICATION_OCTET_STREAM);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class MetadataController {
 | 
					public class MetadataController {
 | 
				
			||||||
@ -159,7 +159,7 @@ public class MetadataController {
 | 
				
			|||||||
        info.setTrapped(trapped);
 | 
					        info.setTrapped(trapped);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        document.setDocumentInformation(info);
 | 
					        document.setDocumentInformation(info);
 | 
				
			||||||
        return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf");
 | 
					        return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,8 +27,8 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
import stirling.software.SPDF.utils.ProcessExecutor;
 | 
					import stirling.software.SPDF.utils.ProcessExecutor;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class OCRController {
 | 
					public class OCRController {
 | 
				
			||||||
@ -189,11 +189,11 @@ public class OCRController {
 | 
				
			|||||||
            Files.delete(sidecarTextPath);
 | 
					            Files.delete(sidecarTextPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Return the zip file containing both the PDF and the text file
 | 
					            // Return the zip file containing both the PDF and the text file
 | 
				
			||||||
            return PdfUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
					            return WebResponseUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // Return the OCR processed PDF as a response
 | 
					            // Return the OCR processed PDF as a response
 | 
				
			||||||
            Files.delete(tempOutputFile);
 | 
					            Files.delete(tempOutputFile);
 | 
				
			||||||
            return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
					            return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.PdfUtils;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class OverlayImageController {
 | 
					public class OverlayImageController {
 | 
				
			||||||
@ -47,7 +48,7 @@ public class OverlayImageController {
 | 
				
			|||||||
            byte[] imageBytes = imageFile.getBytes();
 | 
					            byte[] imageBytes = imageFile.getBytes();
 | 
				
			||||||
            byte[] result = PdfUtils.overlayImage(pdfBytes, imageBytes, x, y, everyPage);
 | 
					            byte[] result = PdfUtils.overlayImage(pdfBytes, imageBytes, x, y, everyPage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return PdfUtils.bytesToWebResponse(result, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
 | 
					            return WebResponseUtils.bytesToWebResponse(result, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            logger.error("Failed to add image to PDF", e);
 | 
					            logger.error("Failed to add image to PDF", e);
 | 
				
			||||||
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
 | 
					            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
 | 
				
			||||||
 | 
				
			|||||||
@ -16,8 +16,8 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
import stirling.software.SPDF.utils.ProcessExecutor;
 | 
					import stirling.software.SPDF.utils.ProcessExecutor;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class RepairController {
 | 
					public class RepairController {
 | 
				
			||||||
@ -60,7 +60,7 @@ public class RepairController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Return the optimized PDF as a response
 | 
					        // Return the optimized PDF as a response
 | 
				
			||||||
        String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_repaired.pdf";
 | 
					        String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_repaired.pdf";
 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
					        return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,8 @@ package stirling.software.SPDF.controller.api.security;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.io.ByteArrayInputStream;
 | 
					import java.io.ByteArrayInputStream;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.ByteArrayOutputStream;
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.InputStream;
 | 
					import java.io.InputStream;
 | 
				
			||||||
@ -51,7 +53,6 @@ import com.itextpdf.signatures.SignatureUtil;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class CertSignController {
 | 
					public class CertSignController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -239,7 +240,7 @@ public class CertSignController {
 | 
				
			|||||||
        System.out.println("Signed PDF size: " + signedPdf.size());
 | 
					        System.out.println("Signed PDF size: " + signedPdf.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        System.out.println("PDF signed = " + isPdfSigned(signedPdf.toByteArray()));
 | 
					        System.out.println("PDF signed = " + isPdfSigned(signedPdf.toByteArray()));
 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(signedPdf.toByteArray(), "example.pdf");
 | 
					        return WebResponseUtils.bytesToWebResponse(signedPdf.toByteArray(), "example.pdf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public boolean isPdfSigned(byte[] pdfData) throws IOException {
 | 
					public boolean isPdfSigned(byte[] pdfData) throws IOException {
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class PasswordController {
 | 
					public class PasswordController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,7 +38,7 @@ public class PasswordController {
 | 
				
			|||||||
            String password) throws IOException {
 | 
					            String password) throws IOException {
 | 
				
			||||||
        PDDocument document = PDDocument.load(fileInput.getBytes(), password);
 | 
					        PDDocument document = PDDocument.load(fileInput.getBytes(), password);
 | 
				
			||||||
        document.setAllSecurityToBeRemoved(true);
 | 
					        document.setAllSecurityToBeRemoved(true);
 | 
				
			||||||
        return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_password_removed.pdf");
 | 
					        return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_password_removed.pdf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @PostMapping(consumes = "multipart/form-data", value = "/add-password")
 | 
					    @PostMapping(consumes = "multipart/form-data", value = "/add-password")
 | 
				
			||||||
@ -105,7 +105,7 @@ public class PasswordController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        document.protect(spp);
 | 
					        document.protect(spp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
 | 
					        return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Operation;
 | 
					import io.swagger.v3.oas.annotations.Operation;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
					import io.swagger.v3.oas.annotations.Parameter;
 | 
				
			||||||
import stirling.software.SPDF.utils.PdfUtils;
 | 
					import stirling.software.SPDF.utils.WebResponseUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class WatermarkController {
 | 
					public class WatermarkController {
 | 
				
			||||||
@ -91,7 +91,7 @@ public class WatermarkController {
 | 
				
			|||||||
            // Close the content stream
 | 
					            // Close the content stream
 | 
				
			||||||
            contentStream.close();
 | 
					            contentStream.close();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
 | 
					        return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -115,6 +115,11 @@ public class OtherWebController {
 | 
				
			|||||||
        return "other/multi-page-layout";
 | 
					        return "other/multi-page-layout";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    
 | 
					    @GetMapping("/scale-pages")
 | 
				
			||||||
 | 
					    @Hidden
 | 
				
			||||||
 | 
					    public String scalePagesFrom(Model model) {
 | 
				
			||||||
 | 
					        model.addAttribute("currentPage", "scale-pages");
 | 
				
			||||||
 | 
					        return "other/scale-pages";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package stirling.software.SPDF.utils;
 | 
					package stirling.software.SPDF.pdf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.awt.geom.Point2D;
 | 
					import java.awt.geom.Point2D;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/main/java/stirling/software/SPDF/utils/GeneralUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/main/java/stirling/software/SPDF/utils/GeneralUtils.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package stirling.software.SPDF.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class GeneralUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static Long convertSizeToBytes(String sizeStr) {
 | 
				
			||||||
 | 
						    if (sizeStr == null) {
 | 
				
			||||||
 | 
						        return null;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    sizeStr = sizeStr.trim().toUpperCase();
 | 
				
			||||||
 | 
						    try {
 | 
				
			||||||
 | 
						        if (sizeStr.endsWith("KB")) {
 | 
				
			||||||
 | 
						            return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024);
 | 
				
			||||||
 | 
						        } else if (sizeStr.endsWith("MB")) {
 | 
				
			||||||
 | 
						            return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024);
 | 
				
			||||||
 | 
						        } else if (sizeStr.endsWith("GB")) {
 | 
				
			||||||
 | 
						            return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024 * 1024);
 | 
				
			||||||
 | 
						        } else if (sizeStr.endsWith("B")) {
 | 
				
			||||||
 | 
						            return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1));
 | 
				
			||||||
 | 
						        } else {
 | 
				
			||||||
 | 
						            // Input string does not have a valid format, handle this case
 | 
				
			||||||
 | 
						        }
 | 
				
			||||||
 | 
						    } catch (NumberFormatException e) {
 | 
				
			||||||
 | 
						        // The numeric part of the input string cannot be parsed, handle this case
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						    
 | 
				
			||||||
 | 
						    return null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					package stirling.software.SPDF.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.image.BufferedImage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ImageProcessingUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) {
 | 
				
			||||||
 | 
						    BufferedImage convertedImage;
 | 
				
			||||||
 | 
						    switch (colorType) {
 | 
				
			||||||
 | 
						        case "greyscale":
 | 
				
			||||||
 | 
						            convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
 | 
				
			||||||
 | 
						            convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
				
			||||||
 | 
						            break;
 | 
				
			||||||
 | 
						        case "blackwhite":
 | 
				
			||||||
 | 
						            convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
 | 
				
			||||||
 | 
						            convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
				
			||||||
 | 
						            break;
 | 
				
			||||||
 | 
						        default:  // full color
 | 
				
			||||||
 | 
						            convertedImage = sourceImage;
 | 
				
			||||||
 | 
						            break;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						    return convertedImage;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package stirling.software.SPDF.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class PDFManipulationUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -92,6 +92,6 @@ public class PDFToFile {
 | 
				
			|||||||
            if (tempOutputDir != null)
 | 
					            if (tempOutputDir != null)
 | 
				
			||||||
                FileUtils.deleteDirectory(tempOutputDir.toFile());
 | 
					                FileUtils.deleteDirectory(tempOutputDir.toFile());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM);
 | 
					        return WebResponseUtils.bytesToWebResponse(fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,8 +8,6 @@ import java.io.File;
 | 
				
			|||||||
import java.io.FileOutputStream;
 | 
					import java.io.FileOutputStream;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.InputStream;
 | 
					import java.io.InputStream;
 | 
				
			||||||
import java.net.URLEncoder;
 | 
					 | 
				
			||||||
import java.nio.charset.StandardCharsets;
 | 
					 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.Files;
 | 
				
			||||||
import java.security.KeyPair;
 | 
					import java.security.KeyPair;
 | 
				
			||||||
import java.security.KeyStore;
 | 
					import java.security.KeyStore;
 | 
				
			||||||
@ -37,39 +35,12 @@ import org.apache.pdfbox.rendering.ImageType;
 | 
				
			|||||||
import org.apache.pdfbox.rendering.PDFRenderer;
 | 
					import org.apache.pdfbox.rendering.PDFRenderer;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
import org.springframework.http.HttpHeaders;
 | 
					 | 
				
			||||||
import org.springframework.http.HttpStatus;
 | 
					 | 
				
			||||||
import org.springframework.http.MediaType;
 | 
					 | 
				
			||||||
import org.springframework.http.ResponseEntity;
 | 
					 | 
				
			||||||
import org.springframework.web.multipart.MultipartFile;
 | 
					import org.springframework.web.multipart.MultipartFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class PdfUtils {
 | 
					public class PdfUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
 | 
					    private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName) throws IOException {
 | 
					 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException {
 | 
					 | 
				
			||||||
        return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType) throws IOException {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Return the PDF as a response
 | 
					 | 
				
			||||||
        HttpHeaders headers = new HttpHeaders();
 | 
					 | 
				
			||||||
        headers.setContentType(mediaType);
 | 
					 | 
				
			||||||
        headers.setContentLength(bytes.length);
 | 
					 | 
				
			||||||
        String encodedDocName = URLEncoder.encode(docName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
 | 
					 | 
				
			||||||
        headers.setContentDispositionFormData("attachment", encodedDocName);
 | 
					 | 
				
			||||||
        return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName) throws IOException {
 | 
					 | 
				
			||||||
        return bytesToWebResponse(bytes, docName, MediaType.APPLICATION_PDF);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI, String filename) throws IOException, Exception {
 | 
					    public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI, String filename) throws IOException, Exception {
 | 
				
			||||||
        try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
 | 
					        try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
 | 
				
			||||||
            PDFRenderer pdfRenderer = new PDFRenderer(document);
 | 
					            PDFRenderer pdfRenderer = new PDFRenderer(document);
 | 
				
			||||||
@ -134,7 +105,7 @@ public class PdfUtils {
 | 
				
			|||||||
                    int numPages = reader.getNumImages(true);
 | 
					                    int numPages = reader.getNumImages(true);
 | 
				
			||||||
                    for (int i = 0; i < numPages; i++) {
 | 
					                    for (int i = 0; i < numPages; i++) {
 | 
				
			||||||
                        BufferedImage pageImage = reader.read(i);
 | 
					                        BufferedImage pageImage = reader.read(i);
 | 
				
			||||||
                        BufferedImage convertedImage = convertColorType(pageImage, colorType);
 | 
					                        BufferedImage convertedImage = ImageProcessingUtils.convertColorType(pageImage, colorType);
 | 
				
			||||||
                        PDImageXObject pdImage = LosslessFactory.createFromImage(doc, convertedImage);
 | 
					                        PDImageXObject pdImage = LosslessFactory.createFromImage(doc, convertedImage);
 | 
				
			||||||
                        addImageToDocument(doc, pdImage, stretchToFit, autoRotate);
 | 
					                        addImageToDocument(doc, pdImage, stretchToFit, autoRotate);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -147,7 +118,7 @@ public class PdfUtils {
 | 
				
			|||||||
                            fos.write(buffer, 0, len);
 | 
					                            fos.write(buffer, 0, len);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        BufferedImage image = ImageIO.read(imageFile);
 | 
					                        BufferedImage image = ImageIO.read(imageFile);
 | 
				
			||||||
                        BufferedImage convertedImage = convertColorType(image, colorType);
 | 
					                        BufferedImage convertedImage = ImageProcessingUtils.convertColorType(image, colorType);
 | 
				
			||||||
                        PDImageXObject pdImage;
 | 
					                        PDImageXObject pdImage;
 | 
				
			||||||
                        if (contentType != null && (contentType.equals("image/jpeg"))) {
 | 
					                        if (contentType != null && (contentType.equals("image/jpeg"))) {
 | 
				
			||||||
                            pdImage = JPEGFactory.createFromImage(doc, convertedImage);
 | 
					                            pdImage = JPEGFactory.createFromImage(doc, convertedImage);
 | 
				
			||||||
@ -170,24 +141,6 @@ public class PdfUtils {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) {
 | 
					 | 
				
			||||||
        BufferedImage convertedImage;
 | 
					 | 
				
			||||||
        switch (colorType) {
 | 
					 | 
				
			||||||
            case "greyscale":
 | 
					 | 
				
			||||||
                convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
 | 
					 | 
				
			||||||
                convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case "blackwhite":
 | 
					 | 
				
			||||||
                convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
 | 
					 | 
				
			||||||
                convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default:  // full color
 | 
					 | 
				
			||||||
                convertedImage = sourceImage;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return convertedImage;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    private static void addImageToDocument(PDDocument doc, PDImageXObject image, boolean stretchToFit, boolean autoRotate) throws IOException {
 | 
					    private static void addImageToDocument(PDDocument doc, PDImageXObject image, boolean stretchToFit, boolean autoRotate) throws IOException {
 | 
				
			||||||
        boolean imageIsLandscape = image.getWidth() > image.getHeight();
 | 
					        boolean imageIsLandscape = image.getWidth() > image.getHeight();
 | 
				
			||||||
        PDRectangle pageSize = PDRectangle.A4;
 | 
					        PDRectangle pageSize = PDRectangle.A4;
 | 
				
			||||||
@ -224,33 +177,6 @@ public class PdfUtils {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static X509Certificate[] loadCertificateChainFromKeystore(InputStream keystoreInputStream, String keystorePassword) throws Exception {
 | 
					 | 
				
			||||||
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
 | 
					 | 
				
			||||||
        keystore.load(keystoreInputStream, keystorePassword.toCharArray());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        String alias = keystore.aliases().nextElement();
 | 
					 | 
				
			||||||
        Certificate[] certChain = keystore.getCertificateChain(alias);
 | 
					 | 
				
			||||||
        X509Certificate[] x509CertChain = new X509Certificate[certChain.length];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (int i = 0; i < certChain.length; i++) {
 | 
					 | 
				
			||||||
            x509CertChain[i] = (X509Certificate) certChain[i];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return x509CertChain;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static KeyPair loadKeyPairFromKeystore(InputStream keystoreInputStream, String keystorePassword) throws Exception {
 | 
					 | 
				
			||||||
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
 | 
					 | 
				
			||||||
        keystore.load(keystoreInputStream, keystorePassword.toCharArray());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        String alias = keystore.aliases().nextElement();
 | 
					 | 
				
			||||||
        PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, keystorePassword.toCharArray());
 | 
					 | 
				
			||||||
        Certificate cert = keystore.getCertificate(alias);
 | 
					 | 
				
			||||||
        PublicKey publicKey = cert.getPublicKey();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return new KeyPair(publicKey, privateKey);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static byte[] overlayImage(byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage) throws IOException {
 | 
					    public static byte[] overlayImage(byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage) throws IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes));
 | 
					        PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes));
 | 
				
			||||||
@ -282,41 +208,7 @@ public class PdfUtils {
 | 
				
			|||||||
        return baos.toByteArray();
 | 
					        return baos.toByteArray();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static ResponseEntity<byte[]> pdfDocToWebResponse(PDDocument document, String docName) throws IOException {
 | 
					 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
        // Open Byte Array and save document to it
 | 
					 | 
				
			||||||
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
					 | 
				
			||||||
        document.save(baos);
 | 
					 | 
				
			||||||
        // Close the document
 | 
					 | 
				
			||||||
        document.close();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return PdfUtils.boasToWebResponse(baos, docName);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    public static Long convertSizeToBytes(String sizeStr) {
 | 
					 | 
				
			||||||
        if (sizeStr == null) {
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        sizeStr = sizeStr.trim().toUpperCase();
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            if (sizeStr.endsWith("KB")) {
 | 
					 | 
				
			||||||
                return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024);
 | 
					 | 
				
			||||||
            } else if (sizeStr.endsWith("MB")) {
 | 
					 | 
				
			||||||
                return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024);
 | 
					 | 
				
			||||||
            } else if (sizeStr.endsWith("GB")) {
 | 
					 | 
				
			||||||
                return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024 * 1024);
 | 
					 | 
				
			||||||
            } else if (sizeStr.endsWith("B")) {
 | 
					 | 
				
			||||||
                return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1));
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                // Input string does not have a valid format, handle this case
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } catch (NumberFormatException e) {
 | 
					 | 
				
			||||||
            // The numeric part of the input string cannot be parsed, handle this case
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					package stirling.software.SPDF.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.net.URLEncoder;
 | 
				
			||||||
 | 
					import java.nio.charset.StandardCharsets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.apache.pdfbox.pdmodel.PDDocument;
 | 
				
			||||||
 | 
					import org.springframework.http.HttpHeaders;
 | 
				
			||||||
 | 
					import org.springframework.http.HttpStatus;
 | 
				
			||||||
 | 
					import org.springframework.http.MediaType;
 | 
				
			||||||
 | 
					import org.springframework.http.ResponseEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class WebResponseUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName) throws IOException {
 | 
				
			||||||
 | 
						    return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException {
 | 
				
			||||||
 | 
						    return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType) throws IOException {
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    // Return the PDF as a response
 | 
				
			||||||
 | 
						    HttpHeaders headers = new HttpHeaders();
 | 
				
			||||||
 | 
						    headers.setContentType(mediaType);
 | 
				
			||||||
 | 
						    headers.setContentLength(bytes.length);
 | 
				
			||||||
 | 
						    String encodedDocName = URLEncoder.encode(docName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
 | 
				
			||||||
 | 
						    headers.setContentDispositionFormData("attachment", encodedDocName);
 | 
				
			||||||
 | 
						    return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName) throws IOException {
 | 
				
			||||||
 | 
						    return bytesToWebResponse(bytes, docName, MediaType.APPLICATION_PDF);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static ResponseEntity<byte[]> pdfDocToWebResponse(PDDocument document, String docName) throws IOException {
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    // Open Byte Array and save document to it
 | 
				
			||||||
 | 
						    ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
				
			||||||
 | 
						    document.save(baos);
 | 
				
			||||||
 | 
						    // Close the document
 | 
				
			||||||
 | 
						    document.close();
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    return boasToWebResponse(baos, docName);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -131,7 +131,10 @@ home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
 | 
				
			|||||||
home.pageLayout.title=Multi-Page Layout
 | 
					home.pageLayout.title=Multi-Page Layout
 | 
				
			||||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
 | 
					home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					home.scalePages.title=Adjust page-scale
 | 
				
			||||||
 | 
					home.scalePages.desc=Change the size of the pages of a PDF document
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
downloadPdf=Download PDF
 | 
					downloadPdf=Download PDF
 | 
				
			||||||
text=Text
 | 
					text=Text
 | 
				
			||||||
@ -144,6 +147,12 @@ pageLayout.header=Multi Page Layout
 | 
				
			|||||||
pageLayout.pagesPerSheet=Pages per sheet:
 | 
					pageLayout.pagesPerSheet=Pages per sheet:
 | 
				
			||||||
pageLayout.submit=Submit
 | 
					pageLayout.submit=Submit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					scalePages.title=Adjust page-scale
 | 
				
			||||||
 | 
					scalePages.header=Adjust page-scale
 | 
				
			||||||
 | 
					scalePages.pageSize=Size of a page of the document.
 | 
				
			||||||
 | 
					scalePages.scaleFactor=Zoom level (crop) of a page.
 | 
				
			||||||
 | 
					scalePages.submit=Submit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
certSign.title=Certificate Signing
 | 
					certSign.title=Certificate Signing
 | 
				
			||||||
certSign.header=Sign a PDF with your certificate (Work in progress)
 | 
					certSign.header=Sign a PDF with your certificate (Work in progress)
 | 
				
			||||||
certSign.selectPDF=Select a PDF File for Signing: 
 | 
					certSign.selectPDF=Select a PDF File for Signing: 
 | 
				
			||||||
 | 
				
			|||||||
@ -131,6 +131,11 @@ home.certSign.desc=Podpisz dokument PDF za pomocą certyfikatu/klucza prywatnego
 | 
				
			|||||||
home.pageLayout.title=Układ wielu stron
 | 
					home.pageLayout.title=Układ wielu stron
 | 
				
			||||||
home.pageLayout.desc=Scal wiele stron dokumentu PDF w jedną stronę
 | 
					home.pageLayout.desc=Scal wiele stron dokumentu PDF w jedną stronę
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					home.scalePages.title=Dopasuj rozmiar stron
 | 
				
			||||||
 | 
					home.scalePages.desc=Dopasuj rozmiar stron wybranego dokumentu PDF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error.pdfPassword=Dokument PDF jest zabezpieczony hasłem, musisz podać prawidłowe hasło.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
downloadPdf=Pobierz PDF
 | 
					downloadPdf=Pobierz PDF
 | 
				
			||||||
text=Tekst
 | 
					text=Tekst
 | 
				
			||||||
font=Czcionka
 | 
					font=Czcionka
 | 
				
			||||||
@ -142,6 +147,12 @@ pageLayout.header=Układ wielu stron
 | 
				
			|||||||
pageLayout.pagesPerSheet=Stron na jednym arkuszu:
 | 
					pageLayout.pagesPerSheet=Stron na jednym arkuszu:
 | 
				
			||||||
pageLayout.submit=Wykonaj
 | 
					pageLayout.submit=Wykonaj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					scalePages.title=Dopasuj rozmiar stron
 | 
				
			||||||
 | 
					scalePages.header=Dopasuj rozmiar stron
 | 
				
			||||||
 | 
					scalePages.pageSize=Rozmiar stron dokumentu:
 | 
				
			||||||
 | 
					scalePages.scaleFactor=Poziom powiększenia (przycięcia) stron:
 | 
				
			||||||
 | 
					scalePages.submit=Wykonaj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
certSign.title=Podpisywanie certyfikatem
 | 
					certSign.title=Podpisywanie certyfikatem
 | 
				
			||||||
certSign.header=Podpisz dokument PDF certyfikatem prywatnym (moduł w budowie)
 | 
					certSign.header=Podpisz dokument PDF certyfikatem prywatnym (moduł w budowie)
 | 
				
			||||||
certSign.selectPDF=Wybierz dokument PDF do podpisania:
 | 
					certSign.selectPDF=Wybierz dokument PDF do podpisania:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								src/main/resources/static/images/scale-pages.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/main/resources/static/images/scale-pages.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrows-fullscreen" viewBox="0 0 16 16">
 | 
				
			||||||
 | 
					  <path fill-rule="evenodd" d="M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707zm4.344 0a.5.5 0 0 1 .707 0l4.096 4.096V11.5a.5.5 0 1 1 1 0v3.975a.5.5 0 0 1-.5.5H11.5a.5.5 0 0 1 0-1h2.768l-4.096-4.096a.5.5 0 0 1 0-.707zm0-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707zm-4.344 0a.5.5 0 0 1-.707 0L1.025 1.732V4.5a.5.5 0 0 1-1 0V.525a.5.5 0 0 1 .5-.5H4.5a.5.5 0 0 1 0 1H1.732l4.096 4.096a.5.5 0 0 1 0 .707z"/>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 730 B  | 
@ -103,7 +103,7 @@ margin-top: 0;
 | 
				
			|||||||
        <div id="content-wrap">
 | 
					        <div id="content-wrap">
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    <div th:insert="~{fragments/navbar.html :: navbar}"></div>
 | 
					    <div th:insert="~{fragments/navbar.html :: navbar}"></div>
 | 
				
			||||||
    
 | 
					    <div th:insert="~{fragments/errorBanner.html :: errorBanner}"></div>
 | 
				
			||||||
      <div class="container">
 | 
					      <div class="container">
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        <div id="support-section">
 | 
					        <div id="support-section">
 | 
				
			||||||
 | 
				
			|||||||
@ -220,267 +220,212 @@ document.addEventListener("DOMContentLoaded", function () {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<th:block th:fragment="fileSelector(name, multiple)"  th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: 'true', notRequired=${notRequired} ?: false">
 | 
					<th:block th:fragment="fileSelector(name, multiple)"  th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: 'true', notRequired=${notRequired} ?: false">
 | 
				
			||||||
    <script>
 | 
					    <script>
 | 
				
			||||||
 | 
						    function showErrorBanner(message, stackTrace) {
 | 
				
			||||||
 | 
						        const errorContainer = document.getElementById("errorContainer");
 | 
				
			||||||
 | 
						        errorContainer.style.display = "block"; // Display the banner
 | 
				
			||||||
 | 
						        document.querySelector("#errorContainer .alert-heading").textContent = "Error";
 | 
				
			||||||
 | 
						        document.querySelector("#errorContainer p").textContent = message;
 | 
				
			||||||
 | 
						        document.querySelector("#traceContent").textContent = stackTrace;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					    	
 | 
				
			||||||
	    $(document).ready(function () {
 | 
						    $(document).ready(function () {
 | 
				
			||||||
	        $('form').submit(async function (event) {
 | 
						        $('form').submit(async function (event) {
 | 
				
			||||||
                const boredWaiting = localStorage.getItem('boredWaiting');
 | 
						            event.preventDefault();
 | 
				
			||||||
                if (boredWaiting === 'enabled') {
 | 
						            
 | 
				
			||||||
                    $('#show-game-btn').show();
 | 
						            const url = this.action;
 | 
				
			||||||
                }
 | 
						            const files = $('#fileInput-input')[0].files;
 | 
				
			||||||
                var processing = "Processing..."
 | 
						            const formData = new FormData(this);
 | 
				
			||||||
                var submitButtonText = $('#submitBtn').text()
 | 
						            const override = $('#override').val() || '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	            $('#submitBtn').text('Processing...');
 | 
						            $('#submitBtn').text('Processing...');
 | 
				
			||||||
                console.log("start download code")
 | 
					 | 
				
			||||||
                var files = $('#fileInput-input')[0].files;
 | 
					 | 
				
			||||||
                var url = this.action;
 | 
					 | 
				
			||||||
                console.log(url)
 | 
					 | 
				
			||||||
                event.preventDefault(); // Prevent the default form handling behavior
 | 
					 | 
				
			||||||
	            
 | 
						            
 | 
				
			||||||
                /* Check if ${multiple} is false */
 | 
						            try {
 | 
				
			||||||
                var multiple = [[${multiple}]] || false;
 | 
						                if (override === 'multi' || files.length > 1 && override !== 'single') {
 | 
				
			||||||
                var override = $('#override').val() || '';
 | 
						                    await submitMultiPdfForm(url, files);
 | 
				
			||||||
                console.log("override=" + override)
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                if([[${remoteCall}]] === true) {
 | 
					 | 
				
			||||||
                    if (override === 'multi' || (!multiple && files.length > 1) && override !== 'single' ) {
 | 
					 | 
				
			||||||
                        console.log("multi parallel download")
 | 
					 | 
				
			||||||
                        await submitMultiPdfForm(event,url);
 | 
					 | 
				
			||||||
	                } else {
 | 
						                } else {
 | 
				
			||||||
                        console.log("start single download")
 | 
						                    const downloadDetails = await handleSingleDownload(url, formData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        // Get the selected download option from localStorage
 | 
						                    // Determine the download option from localStorage
 | 
				
			||||||
	                    const downloadOption = localStorage.getItem('downloadOption');
 | 
						                    const downloadOption = localStorage.getItem('downloadOption');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        var formData = new FormData($('form')[0]);
 | 
						                    // Handle the download action according to the selected option
 | 
				
			||||||
 | 
						                    handleDownloadAction(downloadOption, downloadDetails.blob, downloadDetails.filename);
 | 
				
			||||||
 | 
						                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        // Send the request to the server using the fetch() API
 | 
						                $('#submitBtn').text('Submit');
 | 
				
			||||||
 | 
						            } catch (error) {
 | 
				
			||||||
 | 
						                handleDownloadError(error);
 | 
				
			||||||
 | 
						                $('#submitBtn').text('Submit');
 | 
				
			||||||
 | 
						            }
 | 
				
			||||||
 | 
						        });
 | 
				
			||||||
 | 
						    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    function handleDownloadAction(downloadOption, blob, filename) {
 | 
				
			||||||
 | 
						        const url = URL.createObjectURL(blob);
 | 
				
			||||||
 | 
						        
 | 
				
			||||||
 | 
						        switch (downloadOption) {
 | 
				
			||||||
 | 
						            case 'sameWindow':
 | 
				
			||||||
 | 
						                // Open the file in the same window
 | 
				
			||||||
 | 
						                window.location.href = url;
 | 
				
			||||||
 | 
						                break;
 | 
				
			||||||
 | 
						            case 'newWindow':
 | 
				
			||||||
 | 
						                // Open the file in a new window
 | 
				
			||||||
 | 
						                window.open(url, '_blank');
 | 
				
			||||||
 | 
						                break;
 | 
				
			||||||
 | 
						            default:
 | 
				
			||||||
 | 
						                // Download the file
 | 
				
			||||||
 | 
						                const link = document.createElement('a');
 | 
				
			||||||
 | 
						                link.href = url;
 | 
				
			||||||
 | 
						                link.download = filename;
 | 
				
			||||||
 | 
						                link.click();
 | 
				
			||||||
 | 
						                break;
 | 
				
			||||||
 | 
						        }
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    async function handleSingleDownload(url, formData) {
 | 
				
			||||||
	        const response = await fetch(url, {
 | 
						        const response = await fetch(url, {
 | 
				
			||||||
	            method: 'POST',
 | 
						            method: 'POST',
 | 
				
			||||||
	            body: formData
 | 
						            body: formData
 | 
				
			||||||
	        });
 | 
						        });
 | 
				
			||||||
                        try {
 | 
					
 | 
				
			||||||
                            if (!response) {
 | 
						        if (!response.ok) {
 | 
				
			||||||
                                throw new Error('Received null response for file ' + i);
 | 
						            throw new Error(`HTTP error! status: ${response.status}`);
 | 
				
			||||||
 | 
						        } else {
 | 
				
			||||||
 | 
						            const blob = await response.blob();
 | 
				
			||||||
 | 
						            const filename = getFilenameFromContentDisposition(response.headers.get('Content-Disposition'));
 | 
				
			||||||
 | 
						            return { blob, filename };
 | 
				
			||||||
	        }
 | 
						        }
 | 
				
			||||||
                            console.log("load single download")
 | 
						    }
 | 
				
			||||||
 | 
						    function getFilenameFromContentDisposition(contentDisposition) {
 | 
				
			||||||
 | 
						        let filename;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                
 | 
						        if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
 | 
				
			||||||
                            // Extract the filename from the Content-Disposition header, if present
 | 
						            filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, ''));
 | 
				
			||||||
                            let filename = null;
 | 
					 | 
				
			||||||
                            const contentDispositionHeader = response.headers.get('Content-Disposition');
 | 
					 | 
				
			||||||
                            console.log(contentDispositionHeader)
 | 
					 | 
				
			||||||
                            if (contentDispositionHeader && contentDispositionHeader.indexOf('attachment') !== -1) {
 | 
					 | 
				
			||||||
                                filename = decodeURIComponent(contentDispositionHeader.split('filename=')[1].replace(/"/g, ''));
 | 
					 | 
				
			||||||
	        } else {
 | 
						        } else {
 | 
				
			||||||
	            // If the Content-Disposition header is not present or does not contain the filename, use a default filename
 | 
						            // If the Content-Disposition header is not present or does not contain the filename, use a default filename
 | 
				
			||||||
	            filename = 'download';
 | 
						            filename = 'download';
 | 
				
			||||||
	        }
 | 
						        }
 | 
				
			||||||
                            console.log("filename=" + filename)
 | 
					
 | 
				
			||||||
 | 
						        return filename;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            const contentType = response.headers.get('Content-Type');
 | 
						    async function handlePdfOrImageResponse(response, filename) {
 | 
				
			||||||
                            console.log("contentType=" + contentType)
 | 
						        const downloadOption = localStorage.getItem('downloadOption');
 | 
				
			||||||
                            // Check if the response is a PDF or an image
 | 
					 | 
				
			||||||
                            if (contentType.includes('pdf') || contentType.includes('image')) {
 | 
					 | 
				
			||||||
	        const blob = await response.blob();
 | 
						        const blob = await response.blob();
 | 
				
			||||||
                                console.log("pdf/image")
 | 
						        const url = URL.createObjectURL(blob);
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
                                // Perform the appropriate action based on the download option
 | 
					 | 
				
			||||||
	        if (downloadOption === 'sameWindow') {
 | 
						        if (downloadOption === 'sameWindow') {
 | 
				
			||||||
                                    console.log("same window")
 | 
						            window.location.href = url;
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
                                    // Open the file in the same window
 | 
					 | 
				
			||||||
                                    window.location.href = URL.createObjectURL(blob);
 | 
					 | 
				
			||||||
	        } else if (downloadOption === 'newWindow') {
 | 
						        } else if (downloadOption === 'newWindow') {
 | 
				
			||||||
                                    console.log("new window")
 | 
						            window.open(url, '_blank');
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
                                    // Open the file in a new window
 | 
					 | 
				
			||||||
                                    window.open(URL.createObjectURL(blob), '_blank');
 | 
					 | 
				
			||||||
	        } else {
 | 
						        } else {
 | 
				
			||||||
                                    console.log("else save")
 | 
						            downloadFile(url, filename);
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
                                    // Download the file
 | 
					 | 
				
			||||||
                                    const link = document.createElement('a');
 | 
					 | 
				
			||||||
                                    link.href = URL.createObjectURL(blob);
 | 
					 | 
				
			||||||
                                    link.download = filename;
 | 
					 | 
				
			||||||
                                    link.click();
 | 
					 | 
				
			||||||
	        }
 | 
						        }
 | 
				
			||||||
                            } else if (contentType.includes('json')) {
 | 
						    }
 | 
				
			||||||
                                // Handle the JSON response
 | 
					
 | 
				
			||||||
 | 
						    async function handleJsonResponse(response) {
 | 
				
			||||||
	        const json = await response.json();
 | 
						        const json = await response.json();
 | 
				
			||||||
                                // Format the error message
 | 
					 | 
				
			||||||
	        const errorMessage = JSON.stringify(json, null, 2);
 | 
						        const errorMessage = JSON.stringify(json, null, 2);
 | 
				
			||||||
                                // Display the error message in an alert
 | 
						        if(errorMessage.toLowerCase().includes('the password is incorrect') ||  errorMessage.toLowerCase().includes('Password is not provided')){
 | 
				
			||||||
                                alert(`An error occurred: ${errorMessage}`);
 | 
						            alert('[[#{error.pdfPassword}]]');
 | 
				
			||||||
	        } else {
 | 
						        } else {
 | 
				
			||||||
                                const blob = await response.blob()
 | 
						            showErrorBanner(json.error + ':' + json.message, json.trace);
 | 
				
			||||||
                                console.log("else save 2 zip")
 | 
						        }
 | 
				
			||||||
                                
 | 
					 | 
				
			||||||
                                // For ZIP files or other file types, just download the file
 | 
					 | 
				
			||||||
                                const link = document.createElement('a');
 | 
					 | 
				
			||||||
                                link.href = URL.createObjectURL(blob);
 | 
					 | 
				
			||||||
                                link.download = filename;
 | 
					 | 
				
			||||||
                                link.click();
 | 
					 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
                        } catch(error) {
 | 
					 | 
				
			||||||
                            console.log("error listener")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            // Extract the error message and stack trace from the response
 | 
						    async function handleOtherResponse(response, filename) {
 | 
				
			||||||
 | 
						        const blob = await response.blob();
 | 
				
			||||||
 | 
						        const url = URL.createObjectURL(blob);
 | 
				
			||||||
 | 
						        downloadFile(url, filename);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						    function handleDownloadError(error) {
 | 
				
			||||||
	        const errorMessage = error.message;
 | 
						        const errorMessage = error.message;
 | 
				
			||||||
                            const stackTrace = error.stack;
 | 
						        showErrorBanner(errorMessage);
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
                            // Create an error message to display to the user
 | 
					 | 
				
			||||||
                            const message = `${errorMessage}\n\n${stackTrace}`;
 | 
					 | 
				
			||||||
                        
 | 
					 | 
				
			||||||
                            $('#submitBtn').text(submitButtonText);
 | 
					 | 
				
			||||||
                            
 | 
					 | 
				
			||||||
                            // Display the error message to the user
 | 
					 | 
				
			||||||
                            alert(message);
 | 
					 | 
				
			||||||
                            
 | 
					 | 
				
			||||||
                        };
 | 
					 | 
				
			||||||
                            
 | 
					 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                	//Offline do nothing and let other scripts handle everything
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    let urls = []; // An array to hold all the URLs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    function downloadFile(blob, filename) {
 | 
				
			||||||
 | 
						        const url = URL.createObjectURL(blob);
 | 
				
			||||||
 | 
						        const a = document.createElement('a');
 | 
				
			||||||
 | 
						        a.href = url;
 | 
				
			||||||
 | 
						        a.download = filename;
 | 
				
			||||||
 | 
						        a.click();
 | 
				
			||||||
 | 
						        urls.push(url); // Store the URL so it doesn't get garbage collected too soon
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
                $('#submitBtn').text(submitButtonText);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        async function submitMultiPdfForm(event, url) {
 | 
					 | 
				
			||||||
            // Get the selected PDF files
 | 
					 | 
				
			||||||
            let files = $('#fileInput-input')[0].files;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Get the existing form data
 | 
					 | 
				
			||||||
            let formData = new FormData($('form')[0]);
 | 
					 | 
				
			||||||
            formData.delete('fileInput');
 | 
					 | 
				
			||||||
	    
 | 
						    
 | 
				
			||||||
            // Show the progress bar
 | 
						    async function submitMultiPdfForm(url, files) {
 | 
				
			||||||
            $('#progressBarContainer').show();
 | 
						        const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
 | 
				
			||||||
 | 
						        const zipFiles = files.length > zipThreshold;
 | 
				
			||||||
            // Initialize the progress bar
 | 
						        let jszip = null;
 | 
				
			||||||
	        let progressBar = $('#progressBar');
 | 
						        let progressBar = $('#progressBar');
 | 
				
			||||||
	        progressBar.css('width', '0%');
 | 
						        progressBar.css('width', '0%');
 | 
				
			||||||
	        progressBar.attr('aria-valuenow', 0);
 | 
						        progressBar.attr('aria-valuenow', 0);
 | 
				
			||||||
            progressBar.attr('aria-valuemax', files.length);
 | 
						        progressBar.attr('aria-valuemax', Array.from(files).length);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Check the flag in localStorage, default to 4
 | 
					 | 
				
			||||||
            const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
 | 
					 | 
				
			||||||
            const zipFiles = files.length > zipThreshold;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Initialize JSZip instance if needed
 | 
					 | 
				
			||||||
            let jszip = null;
 | 
					 | 
				
			||||||
	        if (zipFiles) {
 | 
						        if (zipFiles) {
 | 
				
			||||||
	            jszip = new JSZip();
 | 
						            jszip = new JSZip();
 | 
				
			||||||
	        }
 | 
						        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Submit each PDF file in parallel
 | 
						     // Get existing form data
 | 
				
			||||||
            let promises = [];
 | 
						        let formData = new FormData($('form')[0]);
 | 
				
			||||||
            for (let i = 0; i < files.length; i++) {
 | 
						        formData.delete('fileInput');
 | 
				
			||||||
                let promise = new Promise(async function(resolve, reject) {
 | 
					
 | 
				
			||||||
 | 
						        const CONCURRENCY_LIMIT = 8;
 | 
				
			||||||
 | 
						        const chunks = [];
 | 
				
			||||||
 | 
						        for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) {
 | 
				
			||||||
 | 
						            chunks.push(Array.from(files).slice(i, i + CONCURRENCY_LIMIT));
 | 
				
			||||||
 | 
						        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						        for (const chunk of chunks) {
 | 
				
			||||||
 | 
						            const promises = chunk.map(async file => {
 | 
				
			||||||
	                let fileFormData = new FormData();
 | 
						                let fileFormData = new FormData();
 | 
				
			||||||
                    fileFormData.append('fileInput', files[i]);
 | 
						                fileFormData.append('fileInput', file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						                // Add other form data
 | 
				
			||||||
	                for (let pair of formData.entries()) {
 | 
						                for (let pair of formData.entries()) {
 | 
				
			||||||
	                    fileFormData.append(pair[0], pair[1]);
 | 
						                    fileFormData.append(pair[0], pair[1]);
 | 
				
			||||||
	                }
 | 
						                }
 | 
				
			||||||
                    console.log(fileFormData);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	                try {
 | 
						                try {
 | 
				
			||||||
                        let response = await fetch(url, {
 | 
						                    const downloadDetails = await handleSingleDownload(url, fileFormData);
 | 
				
			||||||
                            method: 'POST',
 | 
					 | 
				
			||||||
                            body: fileFormData
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (!response) {
 | 
					 | 
				
			||||||
                            throw new Error('Received null response for file ' + i);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (!response.ok) {
 | 
					 | 
				
			||||||
                            throw new Error(`Error submitting request for file ${i}: ${response.status} ${response.statusText}`);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        let contentDisposition = response.headers.get('content-disposition');
 | 
					 | 
				
			||||||
                        let fileName = "file.pdf"                            
 | 
					 | 
				
			||||||
                        if (!contentDisposition) {
 | 
					 | 
				
			||||||
                            //throw new Error('Content-Disposition header not found for file ' + i);
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            fileName = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, ''));
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        console.log('Received response for file ' + i + ': ' + response);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        let blob = await response.blob();
 | 
					 | 
				
			||||||
	                    if (zipFiles) {
 | 
						                    if (zipFiles) {
 | 
				
			||||||
                            // Add the file to the ZIP archive
 | 
						                        jszip.file(downloadDetails.filename, downloadDetails.blob);
 | 
				
			||||||
                            jszip.file(fileName, blob);
 | 
					 | 
				
			||||||
                            resolve();
 | 
					 | 
				
			||||||
	                    } else {
 | 
						                    } else {
 | 
				
			||||||
                            // Download the file directly
 | 
						                        downloadFile(downloadDetails.blob, downloadDetails.filename);
 | 
				
			||||||
                            let url = window.URL.createObjectURL(blob);
 | 
					 | 
				
			||||||
                            let a = document.createElement('a');
 | 
					 | 
				
			||||||
                            a.href = url;
 | 
					 | 
				
			||||||
                            a.download = fileName;
 | 
					 | 
				
			||||||
                            document.body.appendChild(a);
 | 
					 | 
				
			||||||
                            a.click();
 | 
					 | 
				
			||||||
                            a.remove();
 | 
					 | 
				
			||||||
                            resolve();
 | 
					 | 
				
			||||||
	                    }
 | 
						                    }
 | 
				
			||||||
 | 
						                    updateProgressBar(progressBar, Array.from(files).length);
 | 
				
			||||||
	                } catch (error) {
 | 
						                } catch (error) {
 | 
				
			||||||
                        console.error('Error submitting request for file ' + i + ': ' + error);
 | 
						                    handleDownloadError(error);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        // Set default values or fallbacks for error properties
 | 
					 | 
				
			||||||
                        let status = error && error.status || 500;
 | 
					 | 
				
			||||||
                        let statusText = error && error.statusText || 'Internal Server Error';
 | 
					 | 
				
			||||||
                        let message = error && error.message || 'An error occurred while processing your request.';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        // Reject the Promise to signal that the request has failed
 | 
					 | 
				
			||||||
                        reject();
 | 
					 | 
				
			||||||
                        // Redirect to error page with Spring Boot error parameters
 | 
					 | 
				
			||||||
                        let url = '/error?status=' + status + '&error=' + encodeURIComponent(statusText) + '&message=' + encodeURIComponent(message);
 | 
					 | 
				
			||||||
                        window.location.href = url;
 | 
					 | 
				
			||||||
	                }
 | 
						                }
 | 
				
			||||||
	            });
 | 
						            });
 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Update the progress bar as each request finishes
 | 
					 | 
				
			||||||
                promise.then(function() {
 | 
					 | 
				
			||||||
                    updateProgressBar(progressBar, files);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                promises.push(promise);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Wait for all requests to finish
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
	            await Promise.all(promises);
 | 
						            await Promise.all(promises);
 | 
				
			||||||
            } catch (error) {
 | 
					 | 
				
			||||||
                console.error('Error while uploading files: ' + error);
 | 
					 | 
				
			||||||
	        }
 | 
						        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Update the progress bar
 | 
					 | 
				
			||||||
            progressBar.css('width', '100%');
 | 
					 | 
				
			||||||
            progressBar.attr('aria-valuenow', files.length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // After all requests are finished, download the ZIP file if needed
 | 
					 | 
				
			||||||
	        if (zipFiles) {
 | 
						        if (zipFiles) {
 | 
				
			||||||
	            try {
 | 
						            try {
 | 
				
			||||||
                    let content = await jszip.generateAsync({ type: "blob" });
 | 
						                const content = await jszip.generateAsync({ type: "blob" });
 | 
				
			||||||
                    let url = window.URL.createObjectURL(content);
 | 
						                downloadFile(content, "files.zip");
 | 
				
			||||||
                    let a = document.createElement('a');
 | 
					 | 
				
			||||||
                    a.href = url;
 | 
					 | 
				
			||||||
                    a.download = "files.zip";
 | 
					 | 
				
			||||||
                    document.body.appendChild(a);
 | 
					 | 
				
			||||||
                    a.click();
 | 
					 | 
				
			||||||
                    a.remove();
 | 
					 | 
				
			||||||
	            } catch (error) {
 | 
						            } catch (error) {
 | 
				
			||||||
	                console.error('Error generating ZIP file: ' + error);
 | 
						                console.error('Error generating ZIP file: ' + error);
 | 
				
			||||||
	            }
 | 
						            }
 | 
				
			||||||
	        }
 | 
						        }
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    
 | 
				
			||||||
        function updateProgressBar(progressBar, files) {
 | 
					        function updateProgressBar(progressBar, files) {
 | 
				
			||||||
            let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length);
 | 
					            let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length);
 | 
				
			||||||
            progressBar.css('width', progress + '%');
 | 
					            progressBar.css('width', progress + '%');
 | 
				
			||||||
            progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
 | 
					            progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        window.addEventListener('unload', () => {
 | 
				
			||||||
 | 
					            for (const url of urls) {
 | 
				
			||||||
 | 
					                URL.revokeObjectURL(url);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="custom-file-chooser">
 | 
					    <div class="custom-file-chooser">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										225
									
								
								src/main/resources/templates/fragments/errorBannerPerPage.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								src/main/resources/templates/fragments/errorBannerPerPage.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,225 @@
 | 
				
			|||||||
 | 
					<th:block th:fragment="errorBannerPerPage">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <style scoped>
 | 
				
			||||||
 | 
					    #github-button,
 | 
				
			||||||
 | 
					    #discord-button {
 | 
				
			||||||
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
					      padding: 1rem 2rem;
 | 
				
			||||||
 | 
					      background-color: #008CBA;
 | 
				
			||||||
 | 
					      color: #fff;
 | 
				
			||||||
 | 
					      text-align: center;
 | 
				
			||||||
 | 
					      text-decoration: none;
 | 
				
			||||||
 | 
					      border-radius: 3rem;
 | 
				
			||||||
 | 
					      transition: all 0.3s ease-in-out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #github-button:hover,
 | 
				
			||||||
 | 
					    #discord-button:hover {
 | 
				
			||||||
 | 
					      background-color: #005b7f;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  </style>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  <div id="errorContainer" class="alert alert-danger alert-dismissible fade show" role="alert" style="display: none;">
 | 
				
			||||||
 | 
					  <h4 class="alert-heading">Error</h4>
 | 
				
			||||||
 | 
					  <p></p>
 | 
				
			||||||
 | 
					  <button type="button" class="btn btn-danger" onclick="toggletrace()">Show Stack Trace</button>
 | 
				
			||||||
 | 
					  <button type="button" class="btn btn-secondary" onclick="copytrace()">Copy Stack Trace</button>
 | 
				
			||||||
 | 
					  <button type="button" class="btn btn-info" onclick="showHelp()">Help</button>
 | 
				
			||||||
 | 
					  <button type="button" class="close" data-dismiss="alert" aria-label="Close" onclick="dismissError()">
 | 
				
			||||||
 | 
					    <span aria-hidden="true">×</span>
 | 
				
			||||||
 | 
					  </button>
 | 
				
			||||||
 | 
					  <!-- Stack trace section -->
 | 
				
			||||||
 | 
					  <div id="trace" style="max-height: 0; overflow: hidden;">
 | 
				
			||||||
 | 
					    <div style="background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 3px; padding: 10px; margin-top: 5px;">
 | 
				
			||||||
 | 
					      <pre id="traceContent"></pre>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- Help Modal -->
 | 
				
			||||||
 | 
					   <style scoped>
 | 
				
			||||||
 | 
					   #errorContainer {
 | 
				
			||||||
 | 
					      margin: 20px; /* adjust this value as needed */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
						#helpModalDialog {
 | 
				
			||||||
 | 
					        width: 90%;
 | 
				
			||||||
 | 
					        max-width: 800px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					      #helpModal h1 {
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					        margin-top: 10%;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      #helpModal p {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					        margin-top: 2em;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #helpModal .button:hover {
 | 
				
			||||||
 | 
					          background-color: #005b7f;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      #helpModal .features-container {
 | 
				
			||||||
 | 
					        display: grid;
 | 
				
			||||||
 | 
					        grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
 | 
				
			||||||
 | 
					        gap: 25px 30px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      #helpModal .feature-card {
 | 
				
			||||||
 | 
					        border: 1px solid rgba(0, 0, 0, .125);
 | 
				
			||||||
 | 
					        border-radius: 0.25rem;
 | 
				
			||||||
 | 
					        padding: 1.25rem;
 | 
				
			||||||
 | 
					        display: flex;
 | 
				
			||||||
 | 
					        flex-direction: column;
 | 
				
			||||||
 | 
					        align-items: flex-start;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      #helpModal .feature-card .card-text {
 | 
				
			||||||
 | 
					        flex: 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					#support-section {
 | 
				
			||||||
 | 
					background-color: #f9f9f9;
 | 
				
			||||||
 | 
					padding: 4rem;
 | 
				
			||||||
 | 
					  margin-top: 1rem;
 | 
				
			||||||
 | 
					text-align: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#support-section h1 {
 | 
				
			||||||
 | 
					margin-top: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#support-section p {
 | 
				
			||||||
 | 
					margin-top: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#button-group {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#github-button, #discord-button {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  padding: 1rem 2rem;
 | 
				
			||||||
 | 
					  margin: 1rem;
 | 
				
			||||||
 | 
					  background-color: #008CBA;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					  font-size: 1.2rem;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					  border-radius: 3rem;
 | 
				
			||||||
 | 
					  transition: all 0.3s ease-in-out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#github-button:hover, #discord-button:hover, #home-button:hover {
 | 
				
			||||||
 | 
					  background-color: #005b7f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#home-button {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					        width: 200px;
 | 
				
			||||||
 | 
					        height: 50px;
 | 
				
			||||||
 | 
					        margin: 2em auto;
 | 
				
			||||||
 | 
					        background-color: #008CBA;
 | 
				
			||||||
 | 
					        color: white;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					        line-height: 50px;
 | 
				
			||||||
 | 
					        text-decoration: none;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					        border-radius: 25px;
 | 
				
			||||||
 | 
					  transition: all 0.3s ease-in-out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
						<div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel" aria-hidden="true">
 | 
				
			||||||
 | 
						  <div class="modal-dialog modal-dialog-centered" role="document" id="helpModalDialog">
 | 
				
			||||||
 | 
						    <div class="modal-content">
 | 
				
			||||||
 | 
						      <div class="modal-header">
 | 
				
			||||||
 | 
						        <h5 class="modal-title" id="helpModalLabel">Help</h5>
 | 
				
			||||||
 | 
						        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
 | 
				
			||||||
 | 
						          <span aria-hidden="true">×</span>
 | 
				
			||||||
 | 
						        </button>
 | 
				
			||||||
 | 
						      </div>
 | 
				
			||||||
 | 
						      <div class="modal-body">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						        <div class="container">
 | 
				
			||||||
 | 
						          <div id="support-section">
 | 
				
			||||||
 | 
						            <h1 class="display-2">Oops!</h1>
 | 
				
			||||||
 | 
						            <p class="lead">Sorry for the issue!.</p>
 | 
				
			||||||
 | 
						            <br>
 | 
				
			||||||
 | 
						            <h2>Need help / Found an issue?</h2>
 | 
				
			||||||
 | 
						            <p>If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:</p>
 | 
				
			||||||
 | 
						            <div id="button-group">
 | 
				
			||||||
 | 
						              <a href="https://github.com/Frooodle/Stirling-PDF/issues" id="github-button" target="_blank">GitHub - Submit a ticket</a>
 | 
				
			||||||
 | 
						              <a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank">Discord - Submit Support post</a>
 | 
				
			||||||
 | 
						            </div>  
 | 
				
			||||||
 | 
						            <a href="/" id="home-button">Go to Homepage</a>
 | 
				
			||||||
 | 
						            <a data-dismiss="modal" id="home-button">Close</a>
 | 
				
			||||||
 | 
						          </div>
 | 
				
			||||||
 | 
						        </div>
 | 
				
			||||||
 | 
						      </div>
 | 
				
			||||||
 | 
						    </div>
 | 
				
			||||||
 | 
						  </div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					  <script>
 | 
				
			||||||
 | 
					    var traceVisible = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function toggletrace() {
 | 
				
			||||||
 | 
					      var traceDiv = document.getElementById("trace");
 | 
				
			||||||
 | 
					      if (!traceVisible) {
 | 
				
			||||||
 | 
					        traceDiv.style.maxHeight = "500px";
 | 
				
			||||||
 | 
					        traceVisible = true;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        traceDiv.style.maxHeight = "0px";
 | 
				
			||||||
 | 
					        traceVisible = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      adjustContainerHeight();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function copytrace() {
 | 
				
			||||||
 | 
					      var flip = false
 | 
				
			||||||
 | 
					    	if(!traceVisible) {
 | 
				
			||||||
 | 
					    		 toggletrace()
 | 
				
			||||||
 | 
					    		 flip = true
 | 
				
			||||||
 | 
					    	}
 | 
				
			||||||
 | 
					      var traceContent = document.getElementById("traceContent");
 | 
				
			||||||
 | 
					      var range = document.createRange();
 | 
				
			||||||
 | 
					      range.selectNode(traceContent);
 | 
				
			||||||
 | 
					      window.getSelection().removeAllRanges();
 | 
				
			||||||
 | 
					      window.getSelection().addRange(range);
 | 
				
			||||||
 | 
					      document.execCommand("copy");
 | 
				
			||||||
 | 
					      window.getSelection().removeAllRanges();
 | 
				
			||||||
 | 
					      if(flip){
 | 
				
			||||||
 | 
					    	  toggletrace()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function dismissError() {
 | 
				
			||||||
 | 
					      var errorContainer = document.getElementById("errorContainer");
 | 
				
			||||||
 | 
					      errorContainer.style.display = "none";
 | 
				
			||||||
 | 
					      errorContainer.style.height ="0";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function adjustContainerHeight() {
 | 
				
			||||||
 | 
					      var errorContainer = document.getElementById("errorContainer");
 | 
				
			||||||
 | 
					      var traceDiv = document.getElementById("trace");
 | 
				
			||||||
 | 
					      if (traceVisible) {
 | 
				
			||||||
 | 
					        errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px";
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        errorContainer.style.height = "auto";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function showHelp() {
 | 
				
			||||||
 | 
					        $('#helpModal').modal('show');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  </script>
 | 
				
			||||||
 | 
					</th:block>
 | 
				
			||||||
@ -157,6 +157,7 @@ function compareVersions(version1, version2) {
 | 
				
			|||||||
        <div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'rotate-pdf', 'images/arrow-clockwise.svg', 'home.rotate.title', 'home.rotate.desc')}"></div>
 | 
					        <div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'rotate-pdf', 'images/arrow-clockwise.svg', 'home.rotate.title', 'home.rotate.desc')}"></div>
 | 
				
			||||||
        <div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'remove-pages', 'images/file-earmark-x.svg', 'home.removePages.title', 'home.removePages.desc')}"></div>
 | 
					        <div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'remove-pages', 'images/file-earmark-x.svg', 'home.removePages.title', 'home.removePages.desc')}"></div>
 | 
				
			||||||
		<div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'multi-page-layout', 'images/page-layout.svg', 'home.pageLayout.title', 'home.pageLayout.desc')}"></div>
 | 
							<div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'multi-page-layout', 'images/page-layout.svg', 'home.pageLayout.title', 'home.pageLayout.desc')}"></div>
 | 
				
			||||||
 | 
							<div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'scale-pages', 'images/scale-pages.svg', 'home.scalePages.title', 'home.scalePages.desc')}"></div>
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</li>
 | 
					</li>
 | 
				
			||||||
@ -349,8 +350,8 @@ function compareVersions(version1, version2) {
 | 
				
			|||||||
        </script>
 | 
					        </script>
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    </nav>
 | 
					    </nav>
 | 
				
			||||||
    <div th:insert="~{fragments/errorBanner.html :: errorBanner}"></div>
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
						<div th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></div>
 | 
				
			||||||
    <div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel" aria-hidden="true">
 | 
					    <div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel" aria-hidden="true">
 | 
				
			||||||
    <div class="modal-dialog modal-dialog-centered" role="document">
 | 
					    <div class="modal-dialog modal-dialog-centered" role="document">
 | 
				
			||||||
        <div class="modal-content dark-card">
 | 
					        <div class="modal-content dark-card">
 | 
				
			||||||
 | 
				
			|||||||
@ -137,6 +137,7 @@ filter: invert(0.2) sepia(2) saturate(50) hue-rotate(190deg);
 | 
				
			|||||||
                
 | 
					                
 | 
				
			||||||
                <div th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', svgPath='images/award.svg')}"></div>
 | 
					                <div th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', svgPath='images/award.svg')}"></div>
 | 
				
			||||||
                <div th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', svgPath='images/page-layout.svg')}"></div>
 | 
					                <div th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', svgPath='images/page-layout.svg')}"></div>
 | 
				
			||||||
 | 
					                <div th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', svgPath='images/scale-pages.svg')}"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										39
									
								
								src/main/resources/templates/other/scale-pages.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/main/resources/templates/other/scale-pages.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<th:block th:insert="~{fragments/common :: head(title=#{scalePages.title})}"></th:block>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <div id="page-container">
 | 
				
			||||||
 | 
					        <div id="content-wrap">
 | 
				
			||||||
 | 
					            <div th:insert="~{fragments/navbar.html :: navbar}"></div>
 | 
				
			||||||
 | 
					            <br> <br>
 | 
				
			||||||
 | 
					            <div class="container">
 | 
				
			||||||
 | 
					                <div class="row justify-content-center">
 | 
				
			||||||
 | 
					                    <div class="col-md-6">
 | 
				
			||||||
 | 
					                        <h2 th:text="#{scalePages.header}"></h2>
 | 
				
			||||||
 | 
					                         <form id="scalePagesFrom" th:action="@{scale-pages}" method="post" enctype="multipart/form-data">
 | 
				
			||||||
 | 
					                            <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
 | 
				
			||||||
 | 
					                            <div class="form-group">
 | 
				
			||||||
 | 
						                            <label for="pageSize" th:text="#{scalePages.pageSize}"></label>
 | 
				
			||||||
 | 
												    <select id="pageSize" name="pageSize" required>
 | 
				
			||||||
 | 
												        <option value="A4">A4</option>
 | 
				
			||||||
 | 
												    </select>
 | 
				
			||||||
 | 
											    </div>
 | 
				
			||||||
 | 
					                            <div class="form-group">
 | 
				
			||||||
 | 
						                            <label for="scaleFactor" th:text="#{scalePages.scaleFactor}"></label>
 | 
				
			||||||
 | 
					                                <input type="number" id="scaleFactor" name="scaleFactor" step="any" min="0" value="1">
 | 
				
			||||||
 | 
											    </div>
 | 
				
			||||||
 | 
					                            <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{scalePages.submit}"></button> 
 | 
				
			||||||
 | 
					                        </form>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div th:insert="~{fragments/footer.html :: footer}"></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user