diff --git a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java index 7f429756..6bdb0074 100644 --- a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java @@ -65,6 +65,7 @@ public class EndpointConfiguration { addEndpointToGroup("PageOps", "pdf-organizer"); addEndpointToGroup("PageOps", "rotate-pdf"); addEndpointToGroup("PageOps", "multi-page-layout"); + addEndpointToGroup("PageOps", "scale-pages"); // Adding endpoints to "Convert" group addEndpointToGroup("Convert", "pdf-to-img"); @@ -164,7 +165,7 @@ public class EndpointConfiguration { addEndpointToGroup("Java", "change-metadata"); addEndpointToGroup("Java", "cert-sign"); addEndpointToGroup("Java", "multi-page-layout"); - + addEndpointToGroup("Java", "scale-pages"); //Javascript diff --git a/src/main/java/stirling/software/SPDF/controller/api/MergeController.java b/src/main/java/stirling/software/SPDF/controller/api/MergeController.java index ed68aeb5..3f3ab8c1 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/MergeController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/MergeController.java @@ -17,7 +17,7 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class MergeController { @@ -65,7 +65,7 @@ public class MergeController { // Return the merged PDF as a response - ResponseEntity response = PdfUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf"); + ResponseEntity response = WebResponseUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf"); for (PDDocument doc : documents) { // Close the document after processing diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/MultiPageLayoutController.java b/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java similarity index 94% rename from src/main/java/stirling/software/SPDF/controller/api/other/MultiPageLayoutController.java rename to src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java index 458e06e9..7dc9c51f 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/MultiPageLayoutController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java @@ -1,4 +1,4 @@ -package stirling.software.SPDF.controller.api.other; +package stirling.software.SPDF.controller.api; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -6,7 +6,6 @@ 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; @@ -25,6 +24,7 @@ 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 MultiPageLayoutController { @@ -92,9 +92,8 @@ public class MultiPageLayoutController { outputPdf.close(); byte[] pdfContent = baos.toByteArray(); pdfDoc.close(); - return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"modifiedDocument.pdf\"") - .body(pdfContent); + + return WebResponseUtils.bytesToWebResponse(pdfContent, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_layoutChanged.pdf"); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java index 1873b988..718f8520 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java @@ -2,6 +2,8 @@ package stirling.software.SPDF.controller.api; import java.io.IOException; import io.swagger.v3.oas.annotations.media.Schema; +import stirling.software.SPDF.utils.WebResponseUtils; + import java.util.ArrayList; 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.Parameter; -import stirling.software.SPDF.utils.PdfUtils; @RestController public class RearrangePagesPDFController { @@ -48,7 +49,7 @@ public class RearrangePagesPDFController { int pageIndex = pagesToRemove.get(i); 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); } - return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rearranged.pdf"); + return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rearranged.pdf"); } catch (IOException e) { logger.error("Failed rearranging documents", e); return null; diff --git a/src/main/java/stirling/software/SPDF/controller/api/RotationController.java b/src/main/java/stirling/software/SPDF/controller/api/RotationController.java index 5db10a3e..33bb793b 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/RotationController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/RotationController.java @@ -16,7 +16,7 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class RotationController { @@ -46,7 +46,7 @@ public class RotationController { page.setRotation(page.getRotation() + angle); } - return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf"); + return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf"); } diff --git a/src/main/java/stirling/software/SPDF/controller/api/ScalePagesController.java b/src/main/java/stirling/software/SPDF/controller/api/ScalePagesController.java new file mode 100644 index 00000000..a5f874b2 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/ScalePagesController.java @@ -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 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"); + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java index 74f87cce..5e1e6ac0 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertImgPDFController.java @@ -21,6 +21,7 @@ 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.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class ConvertImgPDFController { @@ -98,7 +99,7 @@ public class ConvertImgPDFController { boolean autoRotate) throws IOException { // Convert the file to PDF and get the resulting bytes 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) { diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java index 039954bb..7b806041 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertOfficeController.java @@ -17,8 +17,8 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class ConvertOfficeController { @@ -72,7 +72,7 @@ public class ConvertOfficeController { // LibreOfficeListener.getInstance().start(); byte[] pdfByteArray = convertToPdf(inputFile); - return PdfUtils.bytesToWebResponse(pdfByteArray, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf"); + return WebResponseUtils.bytesToWebResponse(pdfByteArray, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf"); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java index 207ed0bb..ab269fa3 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java @@ -14,8 +14,8 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class ConvertPDFToPDFA { @@ -58,7 +58,7 @@ public class ConvertPDFToPDFA { // Return the optimized PDF as a response String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_PDFA.pdf"; - return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename); + return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/BlankPageController.java b/src/main/java/stirling/software/SPDF/controller/api/other/BlankPageController.java index 40228e8c..0e17c0ba 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/BlankPageController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/BlankPageController.java @@ -28,9 +28,9 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.ImageFinder; -import stirling.software.SPDF.utils.PdfUtils; +import stirling.software.SPDF.pdf.ImageFinder; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController 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) { e.printStackTrace(); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/CompressController.java b/src/main/java/stirling/software/SPDF/controller/api/other/CompressController.java index f410fe14..d8917bea 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/CompressController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/CompressController.java @@ -31,8 +31,9 @@ import org.springframework.web.multipart.MultipartFile; 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.PdfUtils; +import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class CompressController { @@ -55,7 +56,7 @@ public class CompressController { Long expectedOutputSize = 0L; boolean autoMode = false; if (expectedOutputSizeString != null && expectedOutputSizeString.length() > 1 ) { - expectedOutputSize = PdfUtils.convertSizeToBytes(expectedOutputSizeString); + expectedOutputSize = GeneralUtils.convertSizeToBytes(expectedOutputSizeString); autoMode = true; } @@ -224,7 +225,7 @@ public class CompressController { // Return the optimized PDF as a response String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_Optimized.pdf"; - return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename); + return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImageScansController.java b/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImageScansController.java index 1f6d1c5a..b97ed8e2 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImageScansController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImageScansController.java @@ -31,8 +31,8 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class ExtractImageScansController { @@ -147,11 +147,11 @@ public class ExtractImageScansController { // Clean up the temporary zip file Files.delete(tempZipFile); - return PdfUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM); + return WebResponseUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM); } else { // Return the processed image as a response 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); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImagesController.java b/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImagesController.java index 60313644..66f32539 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImagesController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/ExtractImagesController.java @@ -29,7 +29,7 @@ import org.springframework.web.multipart.MultipartFile; 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.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class ExtractImagesController { @@ -106,7 +106,7 @@ public class ExtractImagesController { // Create ByteArrayResource from byte array 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); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/MetadataController.java b/src/main/java/stirling/software/SPDF/controller/api/other/MetadataController.java index 5840cd64..7eed7c5f 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/MetadataController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/MetadataController.java @@ -19,7 +19,7 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class MetadataController { @@ -159,7 +159,7 @@ public class MetadataController { info.setTrapped(trapped); document.setDocumentInformation(info); - return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf"); + return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf"); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/OCRController.java b/src/main/java/stirling/software/SPDF/controller/api/other/OCRController.java index 12e27c3d..5aa00650 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/OCRController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/OCRController.java @@ -27,8 +27,8 @@ import org.springframework.web.multipart.MultipartFile; 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.PdfUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class OCRController { @@ -189,11 +189,11 @@ public class OCRController { Files.delete(sidecarTextPath); // 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 { // Return the OCR processed PDF as a response Files.delete(tempOutputFile); - return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename); + return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/OverlayImageController.java b/src/main/java/stirling/software/SPDF/controller/api/other/OverlayImageController.java index 0bf8ce83..2afc42c5 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/OverlayImageController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/OverlayImageController.java @@ -15,6 +15,7 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import stirling.software.SPDF.utils.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class OverlayImageController { @@ -47,7 +48,7 @@ public class OverlayImageController { byte[] imageBytes = imageFile.getBytes(); 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) { logger.error("Failed to add image to PDF", e); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/RepairController.java b/src/main/java/stirling/software/SPDF/controller/api/other/RepairController.java index 55cdf83e..58eeabeb 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/RepairController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/RepairController.java @@ -16,8 +16,8 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class RepairController { @@ -60,7 +60,7 @@ public class RepairController { // Return the optimized PDF as a response String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_repaired.pdf"; - return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename); + return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java index a892d044..bd2914bf 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java @@ -2,6 +2,8 @@ package stirling.software.SPDF.controller.api.security; import java.io.ByteArrayInputStream; import io.swagger.v3.oas.annotations.media.Schema; +import stirling.software.SPDF.utils.WebResponseUtils; + import java.io.ByteArrayOutputStream; import java.io.IOException; 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.Parameter; -import stirling.software.SPDF.utils.PdfUtils; @RestController public class CertSignController { @@ -239,7 +240,7 @@ public class CertSignController { System.out.println("Signed PDF size: " + signedPdf.size()); 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 { diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java b/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java index e0fe97c7..97264b9a 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/PasswordController.java @@ -17,7 +17,7 @@ import org.springframework.web.multipart.MultipartFile; 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.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class PasswordController { @@ -38,7 +38,7 @@ public class PasswordController { String password) throws IOException { PDDocument document = PDDocument.load(fileInput.getBytes(), password); 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") @@ -105,7 +105,7 @@ public class PasswordController { document.protect(spp); - return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf"); + return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf"); } diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java b/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java index 46199c63..03be0160 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/WatermarkController.java @@ -19,7 +19,7 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import stirling.software.SPDF.utils.PdfUtils; +import stirling.software.SPDF.utils.WebResponseUtils; @RestController public class WatermarkController { @@ -91,7 +91,7 @@ public class WatermarkController { // Close the content stream contentStream.close(); } - return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf"); + return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf"); } } diff --git a/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java b/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java index e86fb764..95cef9e7 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java @@ -115,6 +115,11 @@ public class OtherWebController { return "other/multi-page-layout"; } - + @GetMapping("/scale-pages") + @Hidden + public String scalePagesFrom(Model model) { + model.addAttribute("currentPage", "scale-pages"); + return "other/scale-pages"; + } } diff --git a/src/main/java/stirling/software/SPDF/utils/ImageFinder.java b/src/main/java/stirling/software/SPDF/pdf/ImageFinder.java similarity index 98% rename from src/main/java/stirling/software/SPDF/utils/ImageFinder.java rename to src/main/java/stirling/software/SPDF/pdf/ImageFinder.java index 9d5ad08e..0f49af76 100644 --- a/src/main/java/stirling/software/SPDF/utils/ImageFinder.java +++ b/src/main/java/stirling/software/SPDF/pdf/ImageFinder.java @@ -1,4 +1,4 @@ -package stirling.software.SPDF.utils; +package stirling.software.SPDF.pdf; import java.awt.geom.Point2D; import java.io.IOException; diff --git a/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java b/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java new file mode 100644 index 00000000..0d8325e4 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java @@ -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; + } + +} diff --git a/src/main/java/stirling/software/SPDF/utils/ImageProcessingUtils.java b/src/main/java/stirling/software/SPDF/utils/ImageProcessingUtils.java new file mode 100644 index 00000000..e34892d5 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/ImageProcessingUtils.java @@ -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; + } + +} diff --git a/src/main/java/stirling/software/SPDF/utils/PDFManipulationUtils.java b/src/main/java/stirling/software/SPDF/utils/PDFManipulationUtils.java new file mode 100644 index 00000000..5718cd8a --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/PDFManipulationUtils.java @@ -0,0 +1,5 @@ +package stirling.software.SPDF.utils; + +public class PDFManipulationUtils { + +} diff --git a/src/main/java/stirling/software/SPDF/utils/PDFToFile.java b/src/main/java/stirling/software/SPDF/utils/PDFToFile.java index ea9308ea..ffe1d93d 100644 --- a/src/main/java/stirling/software/SPDF/utils/PDFToFile.java +++ b/src/main/java/stirling/software/SPDF/utils/PDFToFile.java @@ -92,6 +92,6 @@ public class PDFToFile { if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile()); } - return PdfUtils.bytesToWebResponse(fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM); + return WebResponseUtils.bytesToWebResponse(fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM); } } diff --git a/src/main/java/stirling/software/SPDF/utils/PdfUtils.java b/src/main/java/stirling/software/SPDF/utils/PdfUtils.java index bb172a7b..3956a4a1 100644 --- a/src/main/java/stirling/software/SPDF/utils/PdfUtils.java +++ b/src/main/java/stirling/software/SPDF/utils/PdfUtils.java @@ -8,8 +8,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.security.KeyPair; import java.security.KeyStore; @@ -37,39 +35,12 @@ import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; import org.slf4j.Logger; 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; public class PdfUtils { private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class); - public static ResponseEntity boasToWebResponse(ByteArrayOutputStream baos, String docName) throws IOException { - return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName); - } - - public static ResponseEntity boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException { - return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType); - } - - public static ResponseEntity 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 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 { try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) { PDFRenderer pdfRenderer = new PDFRenderer(document); @@ -134,7 +105,7 @@ public class PdfUtils { int numPages = reader.getNumImages(true); for (int i = 0; i < numPages; i++) { BufferedImage pageImage = reader.read(i); - BufferedImage convertedImage = convertColorType(pageImage, colorType); + BufferedImage convertedImage = ImageProcessingUtils.convertColorType(pageImage, colorType); PDImageXObject pdImage = LosslessFactory.createFromImage(doc, convertedImage); addImageToDocument(doc, pdImage, stretchToFit, autoRotate); } @@ -147,7 +118,7 @@ public class PdfUtils { fos.write(buffer, 0, len); } BufferedImage image = ImageIO.read(imageFile); - BufferedImage convertedImage = convertColorType(image, colorType); + BufferedImage convertedImage = ImageProcessingUtils.convertColorType(image, colorType); PDImageXObject pdImage; if (contentType != null && (contentType.equals("image/jpeg"))) { 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 { boolean imageIsLandscape = image.getWidth() > image.getHeight(); 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 { PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes)); @@ -282,41 +208,7 @@ public class PdfUtils { return baos.toByteArray(); } - public static ResponseEntity 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; - } + } diff --git a/src/main/java/stirling/software/SPDF/utils/WebResponseUtils.java b/src/main/java/stirling/software/SPDF/utils/WebResponseUtils.java new file mode 100644 index 00000000..c986f220 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/WebResponseUtils.java @@ -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 boasToWebResponse(ByteArrayOutputStream baos, String docName) throws IOException { + return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName); + } + + public static ResponseEntity boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException { + return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType); + } + + public static ResponseEntity 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 bytesToWebResponse(byte[] bytes, String docName) throws IOException { + return bytesToWebResponse(bytes, docName, MediaType.APPLICATION_PDF); + } + + public static ResponseEntity 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); + } + +} diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 85632661..b8c634f2 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -131,7 +131,10 @@ home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12) home.pageLayout.title=Multi-Page Layout 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 text=Text @@ -144,6 +147,12 @@ pageLayout.header=Multi Page Layout pageLayout.pagesPerSheet=Pages per sheet: 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.header=Sign a PDF with your certificate (Work in progress) certSign.selectPDF=Select a PDF File for Signing: diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index ef409b97..2cca082f 100644 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -131,6 +131,11 @@ home.certSign.desc=Podpisz dokument PDF za pomocą certyfikatu/klucza prywatnego home.pageLayout.title=Układ wielu 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 text=Tekst font=Czcionka @@ -142,6 +147,12 @@ pageLayout.header=Układ wielu stron pageLayout.pagesPerSheet=Stron na jednym arkuszu: 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.header=Podpisz dokument PDF certyfikatem prywatnym (moduł w budowie) certSign.selectPDF=Wybierz dokument PDF do podpisania: diff --git a/src/main/resources/static/images/scale-pages.svg b/src/main/resources/static/images/scale-pages.svg new file mode 100644 index 00000000..dc0acc3c --- /dev/null +++ b/src/main/resources/static/images/scale-pages.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index 966a9866..dff3fab4 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -103,7 +103,7 @@ margin-top: 0;
- +
diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index 2bf0d875..c7183ee3 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -220,267 +220,212 @@ document.addEventListener("DOMContentLoaded", function () {
diff --git a/src/main/resources/templates/fragments/errorBannerPerPage.html b/src/main/resources/templates/fragments/errorBannerPerPage.html new file mode 100644 index 00000000..c7d492a4 --- /dev/null +++ b/src/main/resources/templates/fragments/errorBannerPerPage.html @@ -0,0 +1,225 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index 78f8508d..275f99f1 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -157,6 +157,7 @@ function compareVersions(version1, version2) {
+
@@ -349,8 +350,8 @@ function compareVersions(version1, version2) { -
- + +