From f6262c82e1c907d729327d3f1450494e4bb4ab45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 21:09:07 +0000 Subject: [PATCH 001/301] Bump org.apache.pdfbox:pdfbox from 2.0.28 to 2.0.29 Bumps org.apache.pdfbox:pdfbox from 2.0.28 to 2.0.29. --- updated-dependencies: - dependency-name: org.apache.pdfbox:pdfbox dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 688bee009..942521160 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' //general PDF - implementation 'org.apache.pdfbox:pdfbox:2.0.28' + implementation 'org.apache.pdfbox:pdfbox:2.0.29' implementation 'org.bouncycastle:bcprov-jdk15on:1.70' implementation 'org.bouncycastle:bcpkix-jdk15on:1.70' implementation 'com.itextpdf:itext7-core:7.2.5' From b5b4636e569fd0153d697a2249187e1c8136489f Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sat, 29 Jul 2023 13:53:30 +0100 Subject: [PATCH 002/301] changes to script executor and init --- scripts/init.sh | 12 +++++++ .../api/converters/ConvertHtmlToPDF.java | 3 +- .../converters/ConvertOfficeController.java | 7 ++-- .../api/converters/ConvertPDFToPDFA.java | 3 +- .../api/converters/ConvertWebsiteToPDF.java | 3 +- .../api/other/BlankPageController.java | 5 +-- .../api/other/CompressController.java | 3 +- .../other/ExtractImageScansController.java | 3 +- .../controller/api/other/OCRController.java | 11 ++++-- .../api/other/RepairController.java | 3 +- .../api/security/PasswordController.java | 24 ++++++------- .../controller/web/SecurityWebController.java | 2 ++ .../software/SPDF/utils/PDFToFile.java | 4 ++- .../software/SPDF/utils/ProcessExecutor.java | 34 ++++++++++++++++--- 14 files changed, 85 insertions(+), 32 deletions(-) diff --git a/scripts/init.sh b/scripts/init.sh index b45bf45f0..99ff22265 100644 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -5,5 +5,17 @@ echo "Copying original files without overwriting existing files" mkdir -p /usr/share/tesseract-ocr cp -rn /usr/share/tesseract-ocr-original/* /usr/share/tesseract-ocr +# Check if TESSERACT_LANGS environment variable is set and is not empty +if [[ -n "$TESSERACT_LANGS" ]]; then + # Convert comma-separated values to a space-separated list + LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ') + + # Install each language pack + for LANG in $LANGS; do + apt-get install -y "tesseract-ocr-$LANG" + done +fi + + # Run the main command exec "$@" \ No newline at end of file diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java index 2d792ee3d..a5878b04b 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java @@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -59,7 +60,7 @@ public class ConvertHtmlToPDF { command.add("weasyprint"); command.add(tempInputFile.toString()); command.add(tempOutputFile.toString()); - int returnCode = 0; + ProcessExecutorResult returnCode; if (originalFilename.endsWith(".zip")) { returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT) .runCommandWithOutputHandling(command, tempInputFile.getParent().toFile()); 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 79be9e2e1..3b9f278f7 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 @@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -41,7 +42,7 @@ public class ConvertOfficeController { // Run the LibreOffice command List command = new ArrayList<>(Arrays.asList("unoconv", "-vvv", "-f", "pdf", "-o", tempOutputFile.toString(), tempInputFile.toString())); - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command); // Read the converted PDF file byte[] pdfBytes = Files.readAllBytes(tempOutputFile); @@ -62,10 +63,10 @@ public class ConvertOfficeController { summary = "Convert a file to a PDF using LibreOffice", description = "This endpoint converts a given file to a PDF using LibreOffice API Input:Any Output:PDF Type:SISO" ) - public ResponseEntity processPdfWithOCR( + public ResponseEntity processFileToPDF( @RequestPart(required = true, value = "fileInput") @Parameter( - description = "The input file to be converted to a PDF file using OCR", + description = "The input file to be converted to a PDF file using LibreOffice", required = true ) MultipartFile inputFile 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 4ff2b4f25..6a99090bb 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 @@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -49,7 +50,7 @@ public class ConvertPDFToPDFA { command.add(tempInputFile.toString()); command.add(tempOutputFile.toString()); - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command); // Read the optimized PDF file byte[] pdfBytes = Files.readAllBytes(tempOutputFile); diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java index 9167a6e43..57cf8f7ff 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertWebsiteToPDF.java @@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -49,7 +50,7 @@ public class ConvertWebsiteToPDF { command.add(URL); command.add(tempOutputFile.toString()); - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT).runCommandWithOutputHandling(command); // Read the optimized PDF file pdfBytes = Files.readAllBytes(tempOutputFile); 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 6ed76edb3..4f505b738 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 @@ -31,6 +31,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -86,10 +87,10 @@ public class BlankPageController { List command = new ArrayList<>(Arrays.asList("python3", System.getProperty("user.dir") + "/scripts/detect-blank-pages.py", tempFile.toString() ,"--threshold", String.valueOf(threshold), "--white_percent", String.valueOf(whitePercent))); // Run CLI command - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command); // does contain data - if (returnCode == 0) { + if (returnCode.getRc() == 0) { System.out.println("page " + pageIndex + " has image which is not blank"); pagesToKeepIndex.add(pageIndex); } else { 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 42ab6a41b..381a68215 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 @@ -34,6 +34,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -116,7 +117,7 @@ public class CompressController { command.add("-sOutputFile=" + tempOutputFile.toString()); command.add(tempInputFile.toString()); - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command); // Check if file size is within expected size or not auto mode so instantly finish long outputFileSize = Files.size(tempOutputFile); 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 f9ac67611..55ff446ca 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 @@ -33,6 +33,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -117,7 +118,7 @@ public class ExtractImageScansController { // Run CLI command - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command); // Read the output photos in temp directory List tempOutputFiles = Files.list(tempDir).sorted().collect(Collectors.toList()); 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 c3c323f5a..d6009c8ac 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 @@ -29,6 +29,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -141,8 +142,12 @@ public class OCRController { command.addAll(Arrays.asList("--language", languageOption, tempInputFile.toString(), tempOutputFile.toString())); // Run CLI command - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command); - + ProcessExecutorResult result = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command); + if(result.getRc() != 0 && result.getMessages().contains("multiprocessing/synchronize.py") && result.getMessages().contains("OSError: [Errno 38] Function not implemented")) { + command.add("--jobs"); + command.add("1"); + result = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command); + } @@ -153,7 +158,7 @@ public class OCRController { List gsCommand = Arrays.asList("gs", "-sDEVICE=pdfwrite", "-dFILTERIMAGE", "-o", tempPdfWithoutImages.toString(), tempOutputFile.toString()); - int gsReturnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(gsCommand); + ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(gsCommand); tempOutputFile = tempPdfWithoutImages; } // Read the OCR processed PDF file 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 536f8c89b..52644080c 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 @@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.utils.ProcessExecutor; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -51,7 +52,7 @@ public class RepairController { command.add(tempInputFile.toString()); - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command); // Read the optimized PDF file byte[] pdfBytes = Files.readAllBytes(tempOutputFile); 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 fa6df6ef9..b3afecf15 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 @@ -35,7 +35,7 @@ public class PasswordController { @RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file from which the password should be removed", required = true) MultipartFile fileInput, - @RequestParam(name = "password") + @RequestPart(name = "password") @Parameter(description = "The password of the PDF file", required = true) String password) throws IOException { PDDocument document = PDDocument.load(fileInput.getBytes(), password); @@ -52,37 +52,37 @@ public class PasswordController { @RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to which the password should be added", required = true) MultipartFile fileInput, - @RequestParam(defaultValue = "", name = "ownerPassword") + @RequestPart(value = "", name = "ownerPassword") @Parameter(description = "The owner password to be added to the PDF file (Restricts what can be done with the document once it is opened)") String ownerPassword, - @RequestParam(defaultValue = "", name = "password") + @RequestPart( name = "password") @Parameter(description = "The password to be added to the PDF file (Restricts the opening of the document itself.)") String password, - @RequestParam(defaultValue = "128", name = "keyLength") + @RequestPart( name = "keyLength") @Parameter(description = "The length of the encryption key", schema = @Schema(allowableValues = {"40", "128", "256"})) int keyLength, - @RequestParam(defaultValue = "false", name = "canAssembleDocument") + @RequestPart( name = "canAssembleDocument") @Parameter(description = "Whether the document assembly is allowed", example = "false") boolean canAssembleDocument, - @RequestParam(defaultValue = "false", name = "canExtractContent") + @RequestPart( name = "canExtractContent") @Parameter(description = "Whether content extraction for accessibility is allowed", example = "false") boolean canExtractContent, - @RequestParam(defaultValue = "false", name = "canExtractForAccessibility") + @RequestPart( name = "canExtractForAccessibility") @Parameter(description = "Whether content extraction for accessibility is allowed", example = "false") boolean canExtractForAccessibility, - @RequestParam(defaultValue = "false", name = "canFillInForm") + @RequestPart( name = "canFillInForm") @Parameter(description = "Whether form filling is allowed", example = "false") boolean canFillInForm, - @RequestParam(defaultValue = "false", name = "canModify") + @RequestPart( name = "canModify") @Parameter(description = "Whether the document modification is allowed", example = "false") boolean canModify, - @RequestParam(defaultValue = "false", name = "canModifyAnnotations") + @RequestPart( name = "canModifyAnnotations") @Parameter(description = "Whether modification of annotations is allowed", example = "false") boolean canModifyAnnotations, - @RequestParam(defaultValue = "false", name = "canPrint") + @RequestPart(name = "canPrint") @Parameter(description = "Whether printing of the document is allowed", example = "false") boolean canPrint, - @RequestParam(defaultValue = "false", name = "canPrintFaithful") + @RequestPart( name = "canPrintFaithful") @Parameter(description = "Whether faithful printing is allowed", example = "false") boolean canPrintFaithful ) throws IOException { diff --git a/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java b/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java index fe176f628..66de400e5 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java @@ -10,6 +10,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; @Controller @Tag(name = "Security", description = "Security APIs") public class SecurityWebController { + + @GetMapping("/add-password") @Hidden public String addPasswordForm(Model model) { diff --git a/src/main/java/stirling/software/SPDF/utils/PDFToFile.java b/src/main/java/stirling/software/SPDF/utils/PDFToFile.java index ffe1d93d6..af658f791 100644 --- a/src/main/java/stirling/software/SPDF/utils/PDFToFile.java +++ b/src/main/java/stirling/software/SPDF/utils/PDFToFile.java @@ -20,6 +20,8 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; + public class PDFToFile { public ResponseEntity processPdfToOfficeFormat(MultipartFile inputFile, String outputFormat, String libreOfficeFilter) throws IOException, InterruptedException { @@ -53,7 +55,7 @@ public class PDFToFile { // Run the LibreOffice command List command = new ArrayList<>( Arrays.asList("soffice", "--infilter=" + libreOfficeFilter, "--convert-to", outputFormat, "--outdir", tempOutputDir.toString(), tempInputFile.toString())); - int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command); + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command); // Get output files List outputFiles = Arrays.asList(tempOutputDir.toFile().listFiles()); diff --git a/src/main/java/stirling/software/SPDF/utils/ProcessExecutor.java b/src/main/java/stirling/software/SPDF/utils/ProcessExecutor.java index f2a7ed55e..fe5c67170 100644 --- a/src/main/java/stirling/software/SPDF/utils/ProcessExecutor.java +++ b/src/main/java/stirling/software/SPDF/utils/ProcessExecutor.java @@ -37,11 +37,12 @@ public class ProcessExecutor { private ProcessExecutor(int semaphoreLimit) { this.semaphore = new Semaphore(semaphoreLimit); } - public int runCommandWithOutputHandling(List command) throws IOException, InterruptedException { + public ProcessExecutorResult runCommandWithOutputHandling(List command) throws IOException, InterruptedException { return runCommandWithOutputHandling(command, null); } - public int runCommandWithOutputHandling(List command, File workingDirectory) throws IOException, InterruptedException { + public ProcessExecutorResult runCommandWithOutputHandling(List command, File workingDirectory) throws IOException, InterruptedException { int exitCode = 1; + String messages = ""; semaphore.acquire(); try { @@ -89,14 +90,16 @@ public class ProcessExecutor { // Wait for the reader threads to finish errorReaderThread.join(); outputReaderThread.join(); - + if (outputLines.size() > 0) { String outputMessage = String.join("\n", outputLines); + messages += outputMessage; System.out.println("Command output:\n" + outputMessage); } if (errorLines.size() > 0) { String errorMessage = String.join("\n", errorLines); + messages += errorMessage; System.out.println("Command error output:\n" + errorMessage); if (exitCode != 0) { throw new IOException("Command process failed with exit code " + exitCode + ". Error message: " + errorMessage); @@ -105,7 +108,28 @@ public class ProcessExecutor { } finally { semaphore.release(); } - return exitCode; + return new ProcessExecutorResult(exitCode, messages); + } + public class ProcessExecutorResult{ + int rc; + String messages; + public ProcessExecutorResult(int rc, String messages) { + this.rc = rc; + this.messages = messages; + } + public int getRc() { + return rc; + } + public void setRc(int rc) { + this.rc = rc; + } + public String getMessages() { + return messages; + } + public void setMessages(String messages) { + this.messages = messages; + } + + } - } From 0732ffa76e6c2a2af8287918f953acdd4c5fa4f9 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sat, 29 Jul 2023 14:31:09 +0100 Subject: [PATCH 003/301] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8e69fb912..f88f9873c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ [![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/paypalme/froodleplex) [![Github Sponser](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle) +[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Frooodle/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af) + This is a powerful locally hosted web based PDF manipulation tool using docker that allows you to perform various operations on PDF files, such as splitting merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application started as a 100% ChatGPT-made application and has evolved to include a wide range of features to handle all your PDF needs. Stirling PDF makes no outbound calls for any record keeping or tracking. From 6b618f3abe85e8786d1514d2e816c7b2eaf70407 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 30 Jul 2023 11:31:46 +0100 Subject: [PATCH 004/301] Watermark fixes --- .../api/security/WatermarkController.java | 4 ++-- src/main/resources/application.properties | 5 ++++- src/main/resources/static/js/downloader.js | 22 +++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) 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 a82712076..f56553914 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 @@ -44,8 +44,8 @@ public class WatermarkController { @Operation(summary = "Add watermark to a PDF file", description = "This endpoint adds a watermark to a given PDF file. Users can specify the watermark type (text or image), rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO") public ResponseEntity addWatermark( @RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to add a watermark") MultipartFile pdfFile, - @RequestPart(required = true) @Parameter(description = "The watermark type (text or image)") String watermarkType, - @RequestPart(required = false) @Parameter(description = "The watermark text") String watermarkText, + @RequestParam(required = true) @Parameter(description = "The watermark type (text or image)") String watermarkType, + @RequestParam(required = false) @Parameter(description = "The watermark text") String watermarkText, @RequestPart(required = false) @Parameter(description = "The watermark image") MultipartFile watermarkImage, @RequestParam(defaultValue = "roman", name = "alphabet") @Parameter(description = "The selected alphabet", diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 06e4edecd..c41183426 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -15,7 +15,10 @@ server.error.whitelabel.enabled=false server.error.include-stacktrace=always server.error.include-exception=true server.error.include-message=always -\ + +#logging.level.org.springframework.web=DEBUG + + server.servlet.session.tracking-modes=cookie server.servlet.context-path=${APP_ROOT_PATH:/} diff --git a/src/main/resources/static/js/downloader.js b/src/main/resources/static/js/downloader.js index e9abdf384..59434264d 100644 --- a/src/main/resources/static/js/downloader.js +++ b/src/main/resources/static/js/downloader.js @@ -14,6 +14,13 @@ $(document).ready(function() { const url = this.action; const files = $('#fileInput-input')[0].files; const formData = new FormData(this); + + // Remove empty file entries + for (let [key, value] of formData.entries()) { + if (value instanceof File && !value.name) { + formData.delete(key); + } + } const override = $('#override').val() || ''; const originalButtonText = $('#submitBtn').text(); $('#submitBtn').text('Processing...'); @@ -159,6 +166,21 @@ async function submitMultiPdfForm(url, files) { let formData = new FormData($('form')[0]); formData.delete('fileInput'); + for (let [key, value] of formData.entries()) { + console.log(key, value); + } + + // Remove empty file entries + for (let [key, value] of formData.entries()) { + if (value instanceof File && !value.name) { + formData.delete(key); + } + } + console.log("## AFTER ## ") + for (let [key, value] of formData.entries()) { + console.log(key, value); + } + const CONCURRENCY_LIMIT = 8; const chunks = []; for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) { From 52a7885f3c73a4f2d0cb4446289f312de278c17e Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 30 Jul 2023 14:43:34 +0100 Subject: [PATCH 005/301] all inf --- .../controller/api/security/PDFExtractor.java | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java b/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java new file mode 100644 index 000000000..4113691d5 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java @@ -0,0 +1,335 @@ +package stirling.software.SPDF.controller.api.security; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import com.itextpdf.kernel.pdf.PdfObject; +import com.itextpdf.forms.PdfAcroForm; +import com.itextpdf.forms.fields.PdfFormField; +import com.itextpdf.kernel.geom.Rectangle; +import com.itextpdf.kernel.pdf.PdfArray; +import com.itextpdf.kernel.pdf.PdfCatalog; +import com.itextpdf.kernel.pdf.PdfDictionary; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfDocumentInfo; +import com.itextpdf.kernel.pdf.PdfEncryption; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfResources; +import com.itextpdf.kernel.pdf.PdfStream; +import com.itextpdf.kernel.pdf.PdfName; +import com.itextpdf.kernel.pdf.PdfViewerPreferences; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.pdf.annot.PdfAnnotation; +import com.itextpdf.kernel.pdf.annot.PdfFileAttachmentAnnotation; +import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation; +import com.itextpdf.kernel.pdf.layer.PdfLayer; +import com.itextpdf.kernel.pdf.layer.PdfOCProperties; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.pdfbox.text.PDFTextStripper; +import java.io.File; +import java.io.FileWriter; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.List; +import java.util.Map; + +public class PDFExtractor { + public static void main(String[] args) { + try { + PDDocument pdfBoxDoc = PDDocument.load(new File("path_to_pdf.pdf")); + ObjectMapper objectMapper = new ObjectMapper(); + ObjectNode jsonOutput = objectMapper.createObjectNode(); + + // Metadata using PDFBox + PDDocumentInformation info = pdfBoxDoc.getDocumentInformation(); + ObjectNode metadata = objectMapper.createObjectNode(); + metadata.put("Title", info.getTitle()); + metadata.put("Author", info.getAuthor()); + metadata.put("Subject", info.getSubject()); + metadata.put("Keywords", info.getKeywords()); + metadata.put("Producer", info.getProducer()); + metadata.put("Creator", info.getCreator()); + metadata.put("CreationDate", formatDate(info.getCreationDate())); + metadata.put("ModificationDate", formatDate(info.getModificationDate())); + metadata.put("Trapped", info.getTrapped()); + jsonOutput.set("Metadata", metadata); + + // Document Information using PDFBox + ObjectNode docInfoNode = objectMapper.createObjectNode(); + docInfoNode.put("Number of pages", pdfBoxDoc.getNumberOfPages()); + docInfoNode.put("PDF version", pdfBoxDoc.getVersion()); + ; + + // Page Mode using iText7 + PdfDocument itextDoc = new PdfDocument(new PdfReader("path_to_pdf.pdf")); + PdfCatalog catalog = itextDoc.getCatalog(); + PdfName pageMode = catalog.getPdfObject().getAsName(PdfName.PageMode); + + ObjectNode itextDocInfo = objectMapper.createObjectNode(); + docInfoNode.put("Page Mode", getPageModeDescription(pageMode));; + + jsonOutput.set("Document Information", docInfoNode); + + for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) { + ObjectNode pageInfo = objectMapper.createObjectNode(); + + // Page-level Information + Rectangle pageSize = itextDoc.getPage(pageNum).getPageSize(); + pageInfo.put("Width", pageSize.getWidth()); + pageInfo.put("Height", pageSize.getHeight()); + pageInfo.put("Rotation", itextDoc.getPage(pageNum).getRotation()); + + // Boxes + pageInfo.put("MediaBox", itextDoc.getPage(pageNum).getMediaBox().toString()); + pageInfo.put("CropBox", itextDoc.getPage(pageNum).getCropBox().toString()); + pageInfo.put("BleedBox", itextDoc.getPage(pageNum).getBleedBox().toString()); + pageInfo.put("TrimBox", itextDoc.getPage(pageNum).getTrimBox().toString()); + pageInfo.put("ArtBox", itextDoc.getPage(pageNum).getArtBox().toString()); + + // Content Extraction + PDFTextStripper textStripper = new PDFTextStripper(); + textStripper.setStartPage(pageNum -1); + textStripper.setEndPage(pageNum - 1); + String pageText = textStripper.getText(pdfBoxDoc); + + pageInfo.put("Text Characters Count", pageText.length()); // + + // Annotations + ArrayNode annotationsArray = objectMapper.createArrayNode(); + List annotations = itextDoc.getPage(pageNum).getAnnotations(); + for (PdfAnnotation annotation : annotations) { + ObjectNode annotationNode = objectMapper.createObjectNode(); + annotationNode.put("Subtype", annotation.getSubtype().toString()); + annotationNode.put("Contents", annotation.getContents().getValue()); + annotationsArray.add(annotationNode); + } + pageInfo.set("Annotations", annotationsArray); + + // Images (simplified) + // This part is non-trivial as images can be embedded in multiple ways in a PDF. + // Here is a basic structure to recognize image XObjects on a page. + ArrayNode imagesArray = objectMapper.createArrayNode(); + PdfResources resources = itextDoc.getPage(pageNum).getResources(); + for (PdfName name : resources.getResourceNames()) { + PdfObject obj = resources.getResource(name); + if (obj instanceof PdfStream) { + PdfStream stream = (PdfStream) obj; + if (PdfName.Image.equals(stream.getAsName(PdfName.Subtype))) { + ObjectNode imageNode = objectMapper.createObjectNode(); + imageNode.put("Width", stream.getAsNumber(PdfName.Width).intValue()); + imageNode.put("Height", stream.getAsNumber(PdfName.Height).intValue()); + PdfObject colorSpace = stream.get(PdfName.ColorSpace); + if (colorSpace != null) { + imageNode.put("ColorSpace", colorSpace.toString()); + } + imagesArray.add(imageNode); + } + } + } + pageInfo.set("Images", imagesArray); + + // Links + ArrayNode linksArray = objectMapper.createArrayNode(); + for (PdfAnnotation annotation : annotations) { + if (annotation instanceof PdfLinkAnnotation) { + PdfLinkAnnotation linkAnnotation = (PdfLinkAnnotation) annotation; + ObjectNode linkNode = objectMapper.createObjectNode(); + linkNode.put("URI", linkAnnotation.getAction().toString()); // Basic, might not work for all links + linksArray.add(linkNode); + } + } + pageInfo.set("Links", linksArray); + + //Fonts + ArrayNode fontsArray = objectMapper.createArrayNode(); + PdfDictionary fontDicts = resources.getResource(PdfName.Font); + if (fontDicts != null) { + for (PdfName key : fontDicts.keySet()) { + PdfDictionary font = fontDicts.getAsDictionary(key); + ObjectNode fontNode = objectMapper.createObjectNode(); + fontNode.put("Name", font.getAsString(PdfName.BaseFont).toString()); + + // Font Subtype (e.g., Type1, TrueType) + if (font.containsKey(PdfName.Subtype)) { + fontNode.put("Subtype", font.getAsName(PdfName.Subtype).toString()); + } + + // Font Descriptor + PdfDictionary fontDescriptor = font.getAsDictionary(PdfName.FontDescriptor); + if (fontDescriptor != null) { + // Italic Angle + if (fontDescriptor.containsKey(PdfName.ItalicAngle)) { + fontNode.put("ItalicAngle", fontDescriptor.getAsNumber(PdfName.ItalicAngle).floatValue()); + } + + // Flags (e.g., italic, bold) + if (fontDescriptor.containsKey(PdfName.Flags)) { + int flags = fontDescriptor.getAsNumber(PdfName.Flags).intValue(); + fontNode.put("IsItalic", (flags & 64) != 0); + fontNode.put("IsBold", (flags & 1) != 0); + } + } + + fontsArray.add(fontNode); + } + } + pageInfo.set("Fonts", fontsArray); + + + + + // Access resources dictionary + PdfDictionary resourcesDict = itextDoc.getPage(pageNum).getResources().getPdfObject(); + + // Color Spaces & ICC Profiles + ArrayNode colorSpacesArray = objectMapper.createArrayNode(); + PdfDictionary colorSpaces = resourcesDict.getAsDictionary(PdfName.ColorSpace); + if (colorSpaces != null) { + for (PdfName name : colorSpaces.keySet()) { + PdfObject colorSpaceObject = colorSpaces.get(name); + if (colorSpaceObject instanceof PdfArray) { + PdfArray colorSpaceArray = (PdfArray) colorSpaceObject; + if (colorSpaceArray.size() > 1 && colorSpaceArray.get(0) instanceof PdfName && PdfName.ICCBased.equals(colorSpaceArray.get(0))) { + ObjectNode iccProfileNode = objectMapper.createObjectNode(); + PdfStream iccStream = (PdfStream) colorSpaceArray.get(1); + byte[] iccData = iccStream.getBytes(); + // TODO: Further decode and analyze the ICC data if needed + iccProfileNode.put("ICC Profile Length", iccData.length); + colorSpacesArray.add(iccProfileNode); + } + } + } + } + pageInfo.set("Color Spaces & ICC Profiles", colorSpacesArray); + + // Other XObjects + ArrayNode xObjectsArray = objectMapper.createArrayNode(); + PdfDictionary xObjects = resourcesDict.getAsDictionary(PdfName.XObject); + if (xObjects != null) { + for (PdfName name : xObjects.keySet()) { + PdfStream xObjectStream = xObjects.getAsStream(name); + ObjectNode xObjectNode = objectMapper.createObjectNode(); + xObjectNode.put("Type", xObjectStream.getAsName(PdfName.Subtype).toString()); + // TODO: Extract further details depending on the XObject type + xObjectsArray.add(xObjectNode); + } + } + pageInfo.set("XObjects", xObjectsArray); + + jsonOutput.set("Page " + pageNum, pageInfo); + } + + PdfAcroForm acroForm = PdfAcroForm.getAcroForm(itextDoc, false); + if (acroForm != null) { + ObjectNode formFieldsNode = objectMapper.createObjectNode(); + for (Map.Entry entry : acroForm.getFormFields().entrySet()) { + formFieldsNode.put(entry.getKey(), entry.getValue().getValueAsString()); + } + jsonOutput.set("FormFields", formFieldsNode); + } + + + + //TODO bookmarks here + + + + + //embeed files TODO size + PdfDictionary embeddedFiles = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names) + .getAsDictionary(PdfName.EmbeddedFiles); + if (embeddedFiles != null) { + ArrayNode embeddedFilesArray = objectMapper.createArrayNode(); + PdfArray namesArray = embeddedFiles.getAsArray(PdfName.Names); + for (int i = 0; i < namesArray.size(); i += 2) { + ObjectNode embeddedFileNode = objectMapper.createObjectNode(); + embeddedFileNode.put("Name", namesArray.getAsString(i).toString()); + // Add other details if required + embeddedFilesArray.add(embeddedFileNode); + } + jsonOutput.set("EmbeddedFiles", embeddedFilesArray); + } + + + //attachments TODO size + ArrayNode attachmentsArray = objectMapper.createArrayNode(); + for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) { + for (PdfAnnotation annotation : itextDoc.getPage(pageNum).getAnnotations()) { + if (annotation instanceof PdfFileAttachmentAnnotation) { + ObjectNode attachmentNode = objectMapper.createObjectNode(); + attachmentNode.put("Name", ((PdfFileAttachmentAnnotation) annotation).getName().toString()); + attachmentNode.put("Description", annotation.getContents().getValue()); + attachmentsArray.add(attachmentNode); + } + } + } + jsonOutput.set("Attachments", attachmentsArray); + + //Javascript + PdfDictionary namesDict = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names); + if (namesDict != null) { + PdfDictionary javascriptDict = namesDict.getAsDictionary(PdfName.JavaScript); + if (javascriptDict != null) { + ArrayNode javascriptArray = objectMapper.createArrayNode(); + PdfArray namesArray = javascriptDict.getAsArray(PdfName.Names); + for (int i = 0; i < namesArray.size(); i += 2) { + ObjectNode jsNode = objectMapper.createObjectNode(); + jsNode.put("JS Name", namesArray.getAsString(i).toString()); + jsNode.put("JS Code", namesArray.getAsString(i + 1).toString()); + javascriptArray.add(jsNode); + } + jsonOutput.set("JavaScripts", javascriptArray); + } + } + + + //TODO size + PdfOCProperties ocProperties = itextDoc.getCatalog().getOCProperties(false); + if (ocProperties != null) { + ArrayNode layersArray = objectMapper.createArrayNode(); + for (PdfLayer layer : ocProperties.getLayers()) { + ObjectNode layerNode = objectMapper.createObjectNode(); + layerNode.put("Name", layer.getPdfObject().getAsString(PdfName.Name).toString()); + layersArray.add(layerNode); + } + jsonOutput.set("Layers", layersArray); + } + + + //TODO Security + + + + + + + // Digital Signatures using iText7 TODO + + + // Save JSON to file + try (FileWriter file = new FileWriter("output.json")) { + file.write(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonOutput)); + file.flush(); + } + + pdfBoxDoc.close(); + itextDoc.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static String formatDate(Calendar calendar) { + if (calendar != null) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return sdf.format(calendar.getTime()); + } else { + return null; + } + } + + private static String getPageModeDescription(PdfName pageMode) { + return pageMode != null ? pageMode.toString().replaceFirst("/", "") : "Unknown"; + } +} From 0da9c62ef84560cbab58b1a5a0bdd55aa3c96ab8 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 30 Jul 2023 21:56:09 +0100 Subject: [PATCH 006/301] all info --- .../controller/api/security/PDFExtractor.java | 675 ++++++++++++++---- .../controller/web/SecurityWebController.java | 7 + .../templates/security/get-info-on-pdf.html | 33 + 3 files changed, 592 insertions(+), 123 deletions(-) create mode 100644 src/main/resources/templates/security/get-info-on-pdf.html diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java b/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java index 4113691d5..2cd429b48 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java @@ -1,8 +1,23 @@ package stirling.software.SPDF.controller.api.security; +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement; +import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureNode; +import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot; +import org.apache.pdfbox.pdmodel.encryption.PDEncryption; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDField; + import com.itextpdf.kernel.pdf.PdfObject; +import com.itextpdf.kernel.pdf.PdfOutline; import com.itextpdf.forms.PdfAcroForm; import com.itextpdf.forms.fields.PdfFormField; import com.itextpdf.kernel.geom.Rectangle; @@ -15,29 +30,64 @@ import com.itextpdf.kernel.pdf.PdfEncryption; import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.kernel.pdf.PdfResources; import com.itextpdf.kernel.pdf.PdfStream; +import com.itextpdf.kernel.pdf.PdfString; import com.itextpdf.kernel.pdf.PdfName; import com.itextpdf.kernel.pdf.PdfViewerPreferences; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.kernel.pdf.annot.PdfAnnotation; import com.itextpdf.kernel.pdf.annot.PdfFileAttachmentAnnotation; import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation; +import com.itextpdf.kernel.pdf.annot.PdfWidgetAnnotation; import com.itextpdf.kernel.pdf.layer.PdfLayer; import com.itextpdf.kernel.pdf.layer.PdfOCProperties; +import com.itextpdf.kernel.xmp.XMPException; +import com.itextpdf.kernel.xmp.XMPMeta; +import com.itextpdf.kernel.xmp.XMPMetaFactory; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import stirling.software.SPDF.utils.WebResponseUtils; + import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.pdfbox.text.PDFTextStripper; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + import java.io.File; +import java.util.HashMap; import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.List; import java.util.Map; - +import java.util.Set; +import java.util.HashSet; +@RestController +@Tag(name = "Security", description = "Security APIs") public class PDFExtractor { - public static void main(String[] args) { - try { - PDDocument pdfBoxDoc = PDDocument.load(new File("path_to_pdf.pdf")); + + static ObjectMapper objectMapper = new ObjectMapper(); + + @PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf") + @Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO") + public ResponseEntity getPdfInfo( + @RequestPart(required = true, value = "fileInput") + @Parameter(description = "The input PDF file to get info on", required = true) MultipartFile inputFile) + throws IOException { + + try ( + PDDocument pdfBoxDoc = PDDocument.load(inputFile.getInputStream()); + PdfDocument itextDoc = new PdfDocument(new PdfReader(inputFile.getInputStream())) + ) { ObjectMapper objectMapper = new ObjectMapper(); ObjectNode jsonOutput = objectMapper.createObjectNode(); @@ -55,22 +105,256 @@ public class PDFExtractor { metadata.put("Trapped", info.getTrapped()); jsonOutput.set("Metadata", metadata); + + + // Total file size of the PDF + long fileSizeInBytes = inputFile.getSize(); + jsonOutput.put("FileSizeInBytes", fileSizeInBytes); + + // Number of words, paragraphs, and images in the entire document + String fullText = new PDFTextStripper().getText(pdfBoxDoc); + String[] words = fullText.split("\\s+"); + int wordCount = words.length; + int paragraphCount = fullText.split("\r\n|\r|\n").length; + jsonOutput.put("WordCount", wordCount); + jsonOutput.put("ParagraphCount", paragraphCount); + // Number of characters in the entire document (including spaces and special characters) + int charCount = fullText.length(); + jsonOutput.put("CharacterCount", charCount); + + + // Initialize the flags and types + boolean hasCompression = false; + String compressionType = "None"; + + // Check for object streams + for (int i = 1; i <= itextDoc.getNumberOfPdfObjects(); i++) { + PdfObject obj = itextDoc.getPdfObject(i); + if (obj != null && obj.isStream() && ((PdfStream) obj).get(PdfName.Type) == PdfName.ObjStm) { + hasCompression = true; + compressionType = "Object Streams"; + break; + } + } + + // If not compressed using object streams, check for compressed Xref tables + if (!hasCompression && itextDoc.getReader().hasRebuiltXref()) { + hasCompression = true; + compressionType = "Compressed Xref or Rebuilt Xref"; + } + jsonOutput.put("Compression", hasCompression); + if(hasCompression) + jsonOutput.put("CompressionType", compressionType); + + String language = pdfBoxDoc.getDocumentCatalog().getLanguage(); + jsonOutput.put("Language", language); + // Document Information using PDFBox ObjectNode docInfoNode = objectMapper.createObjectNode(); docInfoNode.put("Number of pages", pdfBoxDoc.getNumberOfPages()); docInfoNode.put("PDF version", pdfBoxDoc.getVersion()); - ; + // Page Mode using iText7 - PdfDocument itextDoc = new PdfDocument(new PdfReader("path_to_pdf.pdf")); PdfCatalog catalog = itextDoc.getCatalog(); PdfName pageMode = catalog.getPdfObject().getAsName(PdfName.PageMode); - ObjectNode itextDocInfo = objectMapper.createObjectNode(); + + + + PdfAcroForm acroForm = PdfAcroForm.getAcroForm(itextDoc, false); + ObjectNode formFieldsNode = objectMapper.createObjectNode(); + if (acroForm != null) { + for (Map.Entry entry : acroForm.getFormFields().entrySet()) { + formFieldsNode.put(entry.getKey(), entry.getValue().getValueAsString()); + } + } + jsonOutput.set("FormFields", formFieldsNode); + + + + + + //embeed files TODO size + ArrayNode embeddedFilesArray = objectMapper.createArrayNode(); + if(itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names) != null) + { + PdfDictionary embeddedFiles = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names) + .getAsDictionary(PdfName.EmbeddedFiles); + if (embeddedFiles != null) { + + PdfArray namesArray = embeddedFiles.getAsArray(PdfName.Names); + for (int i = 0; i < namesArray.size(); i += 2) { + ObjectNode embeddedFileNode = objectMapper.createObjectNode(); + embeddedFileNode.put("Name", namesArray.getAsString(i).toString()); + // Add other details if required + embeddedFilesArray.add(embeddedFileNode); + } + + } + } + jsonOutput.set("EmbeddedFiles", embeddedFilesArray); + + //attachments TODO size + ArrayNode attachmentsArray = objectMapper.createArrayNode(); + for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) { + for (PdfAnnotation annotation : itextDoc.getPage(pageNum).getAnnotations()) { + if (annotation instanceof PdfFileAttachmentAnnotation) { + ObjectNode attachmentNode = objectMapper.createObjectNode(); + attachmentNode.put("Name", ((PdfFileAttachmentAnnotation) annotation).getName().toString()); + attachmentNode.put("Description", annotation.getContents().getValue()); + attachmentsArray.add(attachmentNode); + } + } + } + jsonOutput.set("Attachments", attachmentsArray); + + //Javascript + PdfDictionary namesDict = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names); + ArrayNode javascriptArray = objectMapper.createArrayNode(); + if (namesDict != null) { + PdfDictionary javascriptDict = namesDict.getAsDictionary(PdfName.JavaScript); + if (javascriptDict != null) { + + PdfArray namesArray = javascriptDict.getAsArray(PdfName.Names); + for (int i = 0; i < namesArray.size(); i += 2) { + ObjectNode jsNode = objectMapper.createObjectNode(); + jsNode.put("JS Name", namesArray.getAsString(i).toString()); + jsNode.put("JS Code", namesArray.getAsString(i + 1).toString()); + javascriptArray.add(jsNode); + } + + } + } + jsonOutput.set("JavaScript", javascriptArray); + + //TODO size + PdfOCProperties ocProperties = itextDoc.getCatalog().getOCProperties(false); + ArrayNode layersArray = objectMapper.createArrayNode(); + if (ocProperties != null) { + + for (PdfLayer layer : ocProperties.getLayers()) { + ObjectNode layerNode = objectMapper.createObjectNode(); + layerNode.put("Name", layer.getPdfObject().getAsString(PdfName.Name).toString()); + layersArray.add(layerNode); + } + + } + jsonOutput.set("Layers", layersArray); + + //TODO Security + + + + + + + // Digital Signatures using iText7 TODO + + + + + PDAcroForm pdAcroForm = pdfBoxDoc.getDocumentCatalog().getAcroForm(); + ArrayNode formFieldsArray2 = objectMapper.createArrayNode(); + if (pdAcroForm != null) { + + for (PDField field : pdAcroForm.getFields()) { + ObjectNode fieldNode = objectMapper.createObjectNode(); + fieldNode.put("FieldName", field.getFullyQualifiedName()); + fieldNode.put("FieldType", field.getFieldType()); + // Add more attributes as needed... + formFieldsArray2.add(fieldNode); + } + + } + jsonOutput.set("FormFields", formFieldsArray2); + + + PDStructureTreeRoot structureTreeRoot = pdfBoxDoc.getDocumentCatalog().getStructureTreeRoot(); + ArrayNode structureTreeArray; + try { + if(structureTreeRoot != null) { + structureTreeArray = exploreStructureTree(structureTreeRoot.getKids()); + jsonOutput.set("StructureTree", structureTreeArray); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + + + + + + + boolean isPdfACompliant = checkOutputIntent(itextDoc, "PDF/A"); + boolean isPdfXCompliant = checkOutputIntent(itextDoc, "PDF/X"); + boolean isPdfECompliant = checkForStandard(itextDoc, "PDF/E"); + boolean isPdfVTCompliant = checkForStandard(itextDoc, "PDF/VT"); + boolean isPdfUACompliant = checkForStandard(itextDoc, "PDF/UA"); + boolean isPdfBCompliant = checkForStandard(itextDoc, "PDF/B"); // If you want to check for PDF/Broadcast, though this isn't an official ISO standard. + boolean isPdfSECCompliant = checkForStandard(itextDoc, "PDF/SEC"); // This might not be effective since PDF/SEC was under development in 2021. + + ObjectNode compliancy = objectMapper.createObjectNode(); + compliancy.put("IsPDF/ACompliant", isPdfACompliant); + compliancy.put("IsPDF/XCompliant", isPdfXCompliant); + compliancy.put("IsPDF/ECompliant", isPdfECompliant); + compliancy.put("IsPDF/VTCompliant", isPdfVTCompliant); + compliancy.put("IsPDF/UACompliant", isPdfUACompliant); + compliancy.put("IsPDF/BCompliant", isPdfBCompliant); + compliancy.put("IsPDF/SECCompliant", isPdfSECCompliant); + + jsonOutput.set("Compliancy", compliancy); + + + + + ArrayNode bookmarksArray = objectMapper.createArrayNode(); + PdfOutline root = itextDoc.getOutlines(false); + if (root != null) { + for (PdfOutline child : root.getAllChildren()) { + addOutlinesToArray(child, bookmarksArray); + } + } + jsonOutput.set("Bookmarks/Outline/TOC", bookmarksArray); + + String xmpString = null; + try { + byte[] xmpBytes = itextDoc.getXmpMetadata(); + if (xmpBytes != null) { + XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(xmpBytes); + xmpString = xmpMeta.dumpObject(); + + } + } catch (XMPException e) { + e.printStackTrace(); + } + jsonOutput.put("XMPMetadata", xmpString); + + + + ObjectNode encryptionNode = objectMapper.createObjectNode(); + if (pdfBoxDoc.isEncrypted()) { + encryptionNode.put("IsEncrypted", true); + + // Retrieve encryption details using getEncryption() + PDEncryption encryption = pdfBoxDoc.getEncryption(); + encryptionNode.put("EncryptionAlgorithm", encryption.getFilter()); + encryptionNode.put("KeyLength", encryption.getLength()); + encryptionNode.put("Permissions", pdfBoxDoc.getCurrentAccessPermission().toString()); + + // Add other encryption-related properties as needed + } else { + encryptionNode.put("IsEncrypted", false); + } + jsonOutput.set("Encryption", encryptionNode); + docInfoNode.put("Page Mode", getPageModeDescription(pageMode));; jsonOutput.set("Document Information", docInfoNode); - + ObjectNode pageInfoParent = objectMapper.createObjectNode(); for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) { ObjectNode pageInfo = objectMapper.createObjectNode(); @@ -79,7 +363,9 @@ public class PDFExtractor { pageInfo.put("Width", pageSize.getWidth()); pageInfo.put("Height", pageSize.getHeight()); pageInfo.put("Rotation", itextDoc.getPage(pageNum).getRotation()); - + pageInfo.put("Page Orientation", getPageOrientation(pageSize.getWidth(),pageSize.getHeight())); + pageInfo.put("Standard Size", getPageSize(pageSize.getWidth(),pageSize.getHeight())); + // Boxes pageInfo.put("MediaBox", itextDoc.getPage(pageNum).getMediaBox().toString()); pageInfo.put("CropBox", itextDoc.getPage(pageNum).getCropBox().toString()); @@ -98,14 +384,25 @@ public class PDFExtractor { // Annotations ArrayNode annotationsArray = objectMapper.createArrayNode(); List annotations = itextDoc.getPage(pageNum).getAnnotations(); - for (PdfAnnotation annotation : annotations) { - ObjectNode annotationNode = objectMapper.createObjectNode(); - annotationNode.put("Subtype", annotation.getSubtype().toString()); - annotationNode.put("Contents", annotation.getContents().getValue()); - annotationsArray.add(annotationNode); - } - pageInfo.set("Annotations", annotationsArray); + int subtypeCount = 0; + int contentsCount = 0; + + for (PdfAnnotation annotation : annotations) { + if(annotation.getSubtype() != null) { + subtypeCount++; // Increase subtype count + } + if(annotation.getContents() != null) { + contentsCount++; // Increase contents count + } + } + + ObjectNode annotationsObject = objectMapper.createObjectNode(); + annotationsObject.put("AnnotationsCount", annotations.size()); + annotationsObject.put("SubtypeCount", subtypeCount); + annotationsObject.put("ContentsCount", contentsCount); + pageInfo.set("Annotations", annotationsObject); + // Images (simplified) // This part is non-trivial as images can be embedded in multiple ways in a PDF. // Here is a basic structure to recognize image XObjects on a page. @@ -129,32 +426,62 @@ public class PDFExtractor { } pageInfo.set("Images", imagesArray); + // Links ArrayNode linksArray = objectMapper.createArrayNode(); + Set uniqueURIs = new HashSet<>(); // To store unique URIs + for (PdfAnnotation annotation : annotations) { if (annotation instanceof PdfLinkAnnotation) { PdfLinkAnnotation linkAnnotation = (PdfLinkAnnotation) annotation; - ObjectNode linkNode = objectMapper.createObjectNode(); - linkNode.put("URI", linkAnnotation.getAction().toString()); // Basic, might not work for all links - linksArray.add(linkNode); + String uri = linkAnnotation.getAction().toString(); + uniqueURIs.add(uri); // Add to set to ensure uniqueness } } + + // Add unique URIs to linksArray + for (String uri : uniqueURIs) { + ObjectNode linkNode = objectMapper.createObjectNode(); + linkNode.put("URI", uri); + linksArray.add(linkNode); + } pageInfo.set("Links", linksArray); //Fonts ArrayNode fontsArray = objectMapper.createArrayNode(); PdfDictionary fontDicts = resources.getResource(PdfName.Font); + Set uniqueSubtypes = new HashSet<>(); // To store unique subtypes + + if (fontDicts != null) { for (PdfName key : fontDicts.keySet()) { + ObjectNode fontNode = objectMapper.createObjectNode(); // Create a new font node for each font PdfDictionary font = fontDicts.getAsDictionary(key); - ObjectNode fontNode = objectMapper.createObjectNode(); - fontNode.put("Name", font.getAsString(PdfName.BaseFont).toString()); + boolean isEmbedded = font.containsKey(PdfName.FontFile) || + font.containsKey(PdfName.FontFile2) || + font.containsKey(PdfName.FontFile3); + fontNode.put("IsEmbedded", isEmbedded); + + + if (font.containsKey(PdfName.Encoding)) { + String encoding = font.getAsName(PdfName.Encoding).toString(); + fontNode.put("Encoding", encoding); + } + + + + if(font.getAsString(PdfName.BaseFont) != null) + fontNode.put("Name", font.getAsString(PdfName.BaseFont).toString()); + + String subtype = null; // Font Subtype (e.g., Type1, TrueType) if (font.containsKey(PdfName.Subtype)) { - fontNode.put("Subtype", font.getAsName(PdfName.Subtype).toString()); + subtype = font.getAsName(PdfName.Subtype).toString(); + uniqueSubtypes.add(subtype); // Add to set to ensure uniqueness } - + fontNode.put("Subtype", subtype); + // Font Descriptor PdfDictionary fontDescriptor = font.getAsDictionary(PdfName.FontDescriptor); if (fontDescriptor != null) { @@ -166,14 +493,53 @@ public class PDFExtractor { // Flags (e.g., italic, bold) if (fontDescriptor.containsKey(PdfName.Flags)) { int flags = fontDescriptor.getAsNumber(PdfName.Flags).intValue(); - fontNode.put("IsItalic", (flags & 64) != 0); - fontNode.put("IsBold", (flags & 1) != 0); + fontNode.put("IsItalic", (flags & 64) != 0); // Existing italic flag + fontNode.put("IsBold", (flags & 1 << 16) != 0); // Existing bold flag + fontNode.put("IsFixedPitch", (flags & 1) != 0); + fontNode.put("IsSerif", (flags & 2) != 0); + fontNode.put("IsSymbolic", (flags & 4) != 0); + fontNode.put("IsScript", (flags & 8) != 0); + fontNode.put("IsNonsymbolic", (flags & 16) != 0); + } + + if (fontDescriptor.containsKey(PdfName.FontFamily)) { + String fontFamily = fontDescriptor.getAsString(PdfName.FontFamily).toString(); + fontNode.put("FontFamily", fontFamily); } - } - fontsArray.add(fontNode); + if (fontDescriptor.containsKey(PdfName.FontStretch)) { + String fontStretch = fontDescriptor.getAsName(PdfName.FontStretch).toString(); + fontNode.put("FontStretch", fontStretch); + } + + if (fontDescriptor != null && fontDescriptor.containsKey(PdfName.FontBBox)) { + PdfArray bbox = fontDescriptor.getAsArray(PdfName.FontBBox); + fontNode.put("FontBoundingBox", bbox.toString()); + } + if (fontDescriptor != null && fontDescriptor.containsKey(PdfName.FontWeight)) { + float fontWeight = fontDescriptor.getAsNumber(PdfName.FontWeight).floatValue(); + fontNode.put("FontWeight", fontWeight); + } + + } + if (font.containsKey(PdfName.ToUnicode)) { + PdfStream toUnicodeStream = font.getAsStream(PdfName.ToUnicode); + // Handle the stream as needed, maybe extract some details or just note its existence + fontNode.put("HasToUnicodeMap", true); + } + if (fontNode.size() > 0) { + fontsArray.add(fontNode); // Add each font node to fontsArray + } } } + + // Add unique subtypes to fontsArray + ArrayNode subtypesArray = objectMapper.createArrayNode(); + for (String subtype : uniqueSubtypes) { + subtypesArray.add(subtype); + } + pageInfo.set("FontSubtypes", subtypesArray); // Changed from Fonts to FontSubtypes + pageInfo.set("Fonts", fontsArray); @@ -204,123 +570,186 @@ public class PDFExtractor { pageInfo.set("Color Spaces & ICC Profiles", colorSpacesArray); // Other XObjects - ArrayNode xObjectsArray = objectMapper.createArrayNode(); + Map xObjectCountMap = new HashMap<>(); // To store the count for each type PdfDictionary xObjects = resourcesDict.getAsDictionary(PdfName.XObject); if (xObjects != null) { for (PdfName name : xObjects.keySet()) { PdfStream xObjectStream = xObjects.getAsStream(name); - ObjectNode xObjectNode = objectMapper.createObjectNode(); - xObjectNode.put("Type", xObjectStream.getAsName(PdfName.Subtype).toString()); - // TODO: Extract further details depending on the XObject type - xObjectsArray.add(xObjectNode); + String xObjectType = xObjectStream.getAsName(PdfName.Subtype).toString(); + + // Increment the count for this type in the map + xObjectCountMap.put(xObjectType, xObjectCountMap.getOrDefault(xObjectType, 0) + 1); } } - pageInfo.set("XObjects", xObjectsArray); - jsonOutput.set("Page " + pageNum, pageInfo); - } - - PdfAcroForm acroForm = PdfAcroForm.getAcroForm(itextDoc, false); - if (acroForm != null) { - ObjectNode formFieldsNode = objectMapper.createObjectNode(); - for (Map.Entry entry : acroForm.getFormFields().entrySet()) { - formFieldsNode.put(entry.getKey(), entry.getValue().getValueAsString()); + // Add the count map to pageInfo (or wherever you want to store it) + ObjectNode xObjectCountNode = objectMapper.createObjectNode(); + for (Map.Entry entry : xObjectCountMap.entrySet()) { + xObjectCountNode.put(entry.getKey(), entry.getValue()); } - jsonOutput.set("FormFields", formFieldsNode); - } + pageInfo.set("XObjectCounts", xObjectCountNode); + + - - - //TODO bookmarks here - - - - - //embeed files TODO size - PdfDictionary embeddedFiles = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names) - .getAsDictionary(PdfName.EmbeddedFiles); - if (embeddedFiles != null) { - ArrayNode embeddedFilesArray = objectMapper.createArrayNode(); - PdfArray namesArray = embeddedFiles.getAsArray(PdfName.Names); - for (int i = 0; i < namesArray.size(); i += 2) { - ObjectNode embeddedFileNode = objectMapper.createObjectNode(); - embeddedFileNode.put("Name", namesArray.getAsString(i).toString()); - // Add other details if required - embeddedFilesArray.add(embeddedFileNode); - } - jsonOutput.set("EmbeddedFiles", embeddedFilesArray); - } - - - //attachments TODO size - ArrayNode attachmentsArray = objectMapper.createArrayNode(); - for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) { - for (PdfAnnotation annotation : itextDoc.getPage(pageNum).getAnnotations()) { - if (annotation instanceof PdfFileAttachmentAnnotation) { - ObjectNode attachmentNode = objectMapper.createObjectNode(); - attachmentNode.put("Name", ((PdfFileAttachmentAnnotation) annotation).getName().toString()); - attachmentNode.put("Description", annotation.getContents().getValue()); - attachmentsArray.add(attachmentNode); + ArrayNode multimediaArray = objectMapper.createArrayNode(); + for (PdfAnnotation annotation : annotations) { + if (PdfName.RichMedia.equals(annotation.getSubtype())) { + ObjectNode multimediaNode = objectMapper.createObjectNode(); + // Extract details from the dictionary as needed + multimediaArray.add(multimediaNode); } } + pageInfo.set("Multimedia", multimediaArray); + + + + pageInfoParent.set("Page " + pageNum, pageInfo); } - jsonOutput.set("Attachments", attachmentsArray); - - //Javascript - PdfDictionary namesDict = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names); - if (namesDict != null) { - PdfDictionary javascriptDict = namesDict.getAsDictionary(PdfName.JavaScript); - if (javascriptDict != null) { - ArrayNode javascriptArray = objectMapper.createArrayNode(); - PdfArray namesArray = javascriptDict.getAsArray(PdfName.Names); - for (int i = 0; i < namesArray.size(); i += 2) { - ObjectNode jsNode = objectMapper.createObjectNode(); - jsNode.put("JS Name", namesArray.getAsString(i).toString()); - jsNode.put("JS Code", namesArray.getAsString(i + 1).toString()); - javascriptArray.add(jsNode); - } - jsonOutput.set("JavaScripts", javascriptArray); - } - } - - //TODO size - PdfOCProperties ocProperties = itextDoc.getCatalog().getOCProperties(false); - if (ocProperties != null) { - ArrayNode layersArray = objectMapper.createArrayNode(); - for (PdfLayer layer : ocProperties.getLayers()) { - ObjectNode layerNode = objectMapper.createObjectNode(); - layerNode.put("Name", layer.getPdfObject().getAsString(PdfName.Name).toString()); - layersArray.add(layerNode); - } - jsonOutput.set("Layers", layersArray); - } - + jsonOutput.set("Per Page Info", pageInfoParent); - //TODO Security - - - - - - - // Digital Signatures using iText7 TODO // Save JSON to file - try (FileWriter file = new FileWriter("output.json")) { - file.write(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonOutput)); - file.flush(); - } - - pdfBoxDoc.close(); - itextDoc.close(); + String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonOutput); + + + + return WebResponseUtils.bytesToWebResponse(jsonString.getBytes(StandardCharsets.UTF_8), "response.json", MediaType.APPLICATION_JSON); + } catch (Exception e) { e.printStackTrace(); } + return null; } - private static String formatDate(Calendar calendar) { + private static void addOutlinesToArray(PdfOutline outline, ArrayNode arrayNode) { + if (outline == null) return; + ObjectNode outlineNode = objectMapper.createObjectNode(); + outlineNode.put("Title", outline.getTitle()); + // You can add other properties if needed + arrayNode.add(outlineNode); + + for (PdfOutline child : outline.getAllChildren()) { + addOutlinesToArray(child, arrayNode); + } + } + public String getPageOrientation(double width, double height) { + if (width > height) { + return "Landscape"; + } else if (height > width) { + return "Portrait"; + } else { + return "Square"; + } + } + public String getPageSize(double width, double height) { + // Common aspect ratios used for standard paper sizes + double[] aspectRatios = {4.0 / 3.0, 3.0 / 2.0, Math.sqrt(2.0), 16.0 / 9.0}; + + // Check if the page matches any common aspect ratio + for (double aspectRatio : aspectRatios) { + if (isCloseToAspectRatio(width, height, aspectRatio)) { + return "Standard"; + } + } + + // If not a standard aspect ratio, consider it as a custom size + return "Custom"; + } + private boolean isCloseToAspectRatio(double width, double height, double aspectRatio) { + // Calculate the aspect ratio of the page + double pageAspectRatio = width / height; + + // Compare the page aspect ratio with the common aspect ratio within a threshold + return Math.abs(pageAspectRatio - aspectRatio) <= 0.05; + } + + public boolean checkForStandard(PdfDocument document, String standardKeyword) { + // Check Output Intents + boolean foundInOutputIntents = checkOutputIntent(document, standardKeyword); + if (foundInOutputIntents) return true; + + // Check XMP Metadata (rudimentary) + try { + byte[] metadataBytes = document.getXmpMetadata(); + if (metadataBytes != null) { + XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(metadataBytes); + String xmpString = xmpMeta.dumpObject(); + if (xmpString.contains(standardKeyword)) { + return true; + } + } + } catch (XMPException e) { + e.printStackTrace(); + } + + return false; + } + + + public boolean checkOutputIntent(PdfDocument document, String standard) { + PdfArray outputIntents = document.getCatalog().getPdfObject().getAsArray(PdfName.OutputIntents); + if (outputIntents != null && !outputIntents.isEmpty()) { + for (int i = 0; i < outputIntents.size(); i++) { + PdfDictionary outputIntentDict = outputIntents.getAsDictionary(i); + if (outputIntentDict != null) { + PdfString s = outputIntentDict.getAsString(PdfName.S); + if (s != null && s.toString().contains(standard)) { + return true; + } + } + } + } + return false; + } + + public ArrayNode exploreStructureTree(List nodes) { + ArrayNode elementsArray = objectMapper.createArrayNode(); + if (nodes != null) { + for (Object obj : nodes) { + if (obj instanceof PDStructureNode) { + PDStructureNode node = (PDStructureNode) obj; + ObjectNode elementNode = objectMapper.createObjectNode(); + + if (node instanceof PDStructureElement) { + PDStructureElement structureElement = (PDStructureElement) node; + elementNode.put("Type", structureElement.getStructureType()); + elementNode.put("Content", getContent(structureElement)); + + // Recursively explore child elements + ArrayNode childElements = exploreStructureTree(structureElement.getKids()); + if (childElements.size() > 0) { + elementNode.set("Children", childElements); + } + } + elementsArray.add(elementNode); + } + } + } + return elementsArray; + } + + + public String getContent(PDStructureElement structureElement) { + StringBuilder contentBuilder = new StringBuilder(); + + for (Object item : structureElement.getKids()) { + if (item instanceof COSString) { + COSString cosString = (COSString) item; + contentBuilder.append(cosString.getString()); + } else if (item instanceof PDStructureElement) { + // For simplicity, we're handling only COSString and PDStructureElement here + // but a more comprehensive method would handle other types too + contentBuilder.append(getContent((PDStructureElement) item)); + } + } + + return contentBuilder.toString(); + } + + + private String formatDate(Calendar calendar) { if (calendar != null) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(calendar.getTime()); @@ -329,7 +758,7 @@ public class PDFExtractor { } } - private static String getPageModeDescription(PdfName pageMode) { + private String getPageModeDescription(PdfName pageMode) { return pageMode != null ? pageMode.toString().replaceFirst("/", "") : "Unknown"; } } diff --git a/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java b/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java index 66de400e5..3857cc9ed 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java @@ -52,4 +52,11 @@ public class SecurityWebController { model.addAttribute("currentPage", "sanitize-pdf"); return "security/sanitize-pdf"; } + + @GetMapping("/get-info-on-pdf") + @Hidden + public String getInfo(Model model) { + model.addAttribute("currentPage", "get-info-on-pdf"); + return "security/get-info-on-pdf"; + } } diff --git a/src/main/resources/templates/security/get-info-on-pdf.html b/src/main/resources/templates/security/get-info-on-pdf.html new file mode 100644 index 000000000..36a0bb6e9 --- /dev/null +++ b/src/main/resources/templates/security/get-info-on-pdf.html @@ -0,0 +1,33 @@ + + + + + + + + +
+
+
+

+
+
+
+

+

+

+
+
+ + +
+ +
+
+
+ +
+
+
+ + \ No newline at end of file From 77411e94a48bc35a35a316c334ac1a1b664d1424 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Tue, 1 Aug 2023 00:03:13 +0100 Subject: [PATCH 007/301] new features --- build.gradle | 3 +- .../api/ToSinglePageController.java | 86 +++++++++++++++++ .../api/converters/ConvertHtmlToPDF.java | 81 ++-------------- .../api/converters/ConvertMarkdownToPdf.java | 52 ++++++++++ .../web/ConverterWebController.java | 9 +- .../controller/web/GeneralWebController.java | 14 +++ .../software/SPDF/utils/FileToPdf.java | 95 +++++++++++++++++++ .../software/SPDF/utils/WebResponseUtils.java | 17 ++++ src/main/resources/messages_en_GB.properties | 19 ++++ src/main/resources/static/images/extract.svg | 3 + src/main/resources/static/images/info.svg | 4 + src/main/resources/static/images/markdown.svg | 3 + .../resources/static/images/single-page.svg | 4 + .../resources/templates/auto-split-pdf.html | 2 +- .../templates/convert/markdown-to-pdf.html | 30 ++++++ .../resources/templates/extract-page.html | 33 +++++++ src/main/resources/templates/home.html | 7 ++ .../templates/pdf-to-single-page.html | 29 ++++++ 18 files changed, 413 insertions(+), 78 deletions(-) create mode 100644 src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java create mode 100644 src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java create mode 100644 src/main/java/stirling/software/SPDF/utils/FileToPdf.java create mode 100644 src/main/resources/static/images/extract.svg create mode 100644 src/main/resources/static/images/info.svg create mode 100644 src/main/resources/static/images/markdown.svg create mode 100644 src/main/resources/static/images/single-page.svg create mode 100644 src/main/resources/templates/convert/markdown-to-pdf.html create mode 100644 src/main/resources/templates/extract-page.html create mode 100644 src/main/resources/templates/pdf-to-single-page.html diff --git a/build.gradle b/build.gradle index 688bee009..e851d9a50 100644 --- a/build.gradle +++ b/build.gradle @@ -61,8 +61,9 @@ dependencies { implementation 'com.itextpdf:itext7-core:7.2.5' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'io.micrometer:micrometer-core' - implementation group: 'com.google.zxing', name: 'core', version: '3.5.1' + // https://mvnrepository.com/artifact/org.commonmark/commonmark + implementation 'org.commonmark:commonmark:0.21.0' developmentOnly("org.springframework.boot:spring-boot-devtools") diff --git a/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java b/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java new file mode 100644 index 000000000..2c249b85f --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/ToSinglePageController.java @@ -0,0 +1,86 @@ +package stirling.software.SPDF.controller.api; + +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import com.itextpdf.kernel.pdf.*; +import com.itextpdf.kernel.pdf.xobject.PdfFormXObject; +import com.itextpdf.kernel.geom.PageSize; +import com.itextpdf.kernel.geom.Rectangle; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Image; +import java.util.ArrayList; +import java.util.List; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageTree; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +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.tags.Tag; +import stirling.software.SPDF.utils.WebResponseUtils; +import org.apache.pdfbox.pdmodel.*; +import org.apache.pdfbox.multipdf.PDFMergerUtility; +@RestController +@Tag(name = "General", description = "General APIs") +public class ToSinglePageController { + + private static final Logger logger = LoggerFactory.getLogger(ToSinglePageController.class); + + + @PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page") + @Operation( + summary = "Convert a multi-page PDF into a single long page PDF", + description = "This endpoint converts a multi-page PDF document into a single paged PDF document. The width of the single page will be same as the input's width, but the height will be the sum of all the pages' heights. Input:PDF Output:PDF Type:SISO" + ) + public ResponseEntity pdfToSinglePage( + @RequestPart(required = true, value = "fileInput") + @Parameter(description = "The input multi-page PDF file to be converted into a single page", required = true) + MultipartFile file) throws IOException { + + PdfReader reader = new PdfReader(file.getInputStream()); + PdfDocument sourceDocument = new PdfDocument(reader); + + float totalHeight = 0; + float width = 0; + + for (int i = 1; i <= sourceDocument.getNumberOfPages(); i++) { + Rectangle pageSize = sourceDocument.getPage(i).getPageSize(); + totalHeight += pageSize.getHeight(); + if(width < pageSize.getWidth()) + width = pageSize.getWidth(); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter writer = new PdfWriter(baos); + PdfDocument newDocument = new PdfDocument(writer); + PageSize newPageSize = new PageSize(width, totalHeight); + newDocument.addNewPage(newPageSize); + + Document layoutDoc = new Document(newDocument); + float yOffset = totalHeight; + + for (int i = 1; i <= sourceDocument.getNumberOfPages(); i++) { + PdfFormXObject pageCopy = sourceDocument.getPage(i).copyAsFormXObject(newDocument); + Image copiedPage = new Image(pageCopy); + copiedPage.setFixedPosition(0, yOffset - sourceDocument.getPage(i).getPageSize().getHeight()); + yOffset -= sourceDocument.getPage(i).getPageSize().getHeight(); + layoutDoc.add(copiedPage); + } + + layoutDoc.close(); + sourceDocument.close(); + + byte[] result = baos.toByteArray(); + return WebResponseUtils.bytesToWebResponse(result, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_singlePage.pdf"); + } +} \ No newline at end of file diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java index a5878b04b..e054d7f03 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java @@ -19,6 +19,7 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import stirling.software.SPDF.utils.FileToPdf; import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; @@ -44,87 +45,17 @@ public class ConvertHtmlToPDF { String originalFilename = fileInput.getOriginalFilename(); if (originalFilename == null || (!originalFilename.endsWith(".html") && !originalFilename.endsWith(".zip"))) { throw new IllegalArgumentException("File must be either .html or .zip format."); - } - Path tempOutputFile = Files.createTempFile("output_", ".pdf"); - Path tempInputFile = null; - byte[] pdfBytes; - try { - if (originalFilename.endsWith(".html")) { - tempInputFile = Files.createTempFile("input_", ".html"); - Files.write(tempInputFile, fileInput.getBytes()); - } else { - tempInputFile = unzipAndGetMainHtml(fileInput); - } - - List command = new ArrayList<>(); - command.add("weasyprint"); - command.add(tempInputFile.toString()); - command.add(tempOutputFile.toString()); - ProcessExecutorResult returnCode; - if (originalFilename.endsWith(".zip")) { - returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT) - .runCommandWithOutputHandling(command, tempInputFile.getParent().toFile()); - } else { - - returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT) - .runCommandWithOutputHandling(command); - } - - pdfBytes = Files.readAllBytes(tempOutputFile); - } finally { - // Clean up temporary files - Files.delete(tempOutputFile); - Files.delete(tempInputFile); - - if (originalFilename.endsWith(".zip")) { - GeneralUtils.deleteDirectory(tempInputFile.getParent()); - } - } + }byte[] pdfBytes = FileToPdf.convertHtmlToPdf( fileInput.getBytes(), originalFilename); + String outputFilename = originalFilename.replaceFirst("[.][^.]+$", "") + ".pdf"; // Remove file extension and append .pdf + return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); } - - - private Path unzipAndGetMainHtml(MultipartFile zipFile) throws IOException { - Path tempDirectory = Files.createTempDirectory("unzipped_"); - try (ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(zipFile.getBytes()))) { - ZipEntry entry = zipIn.getNextEntry(); - while (entry != null) { - Path filePath = tempDirectory.resolve(entry.getName()); - if (entry.isDirectory()) { - Files.createDirectories(filePath); // Explicitly create the directory structure - } else { - Files.createDirectories(filePath.getParent()); // Create parent directories if they don't exist - Files.copy(zipIn, filePath); - } - zipIn.closeEntry(); - entry = zipIn.getNextEntry(); - } - } - - //search for the main HTML file. - try (Stream walk = Files.walk(tempDirectory)) { - List htmlFiles = walk.filter(file -> file.toString().endsWith(".html")) - .collect(Collectors.toList()); - - if (htmlFiles.isEmpty()) { - throw new IOException("No HTML files found in the unzipped directory."); - } - - // Prioritize 'index.html' if it exists, otherwise use the first .html file - for (Path htmlFile : htmlFiles) { - if (htmlFile.getFileName().toString().equals("index.html")) { - return htmlFile; - } - } - - return htmlFiles.get(0); - } - } + - + } diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java new file mode 100644 index 000000000..c1bc1b73a --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java @@ -0,0 +1,52 @@ +package stirling.software.SPDF.controller.api.converters; + +import java.io.IOException; + +import org.commonmark.node.Node; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import stirling.software.SPDF.utils.FileToPdf; +import stirling.software.SPDF.utils.WebResponseUtils; + +@RestController +@Tag(name = "Convert", description = "Convert APIs") +public class ConvertMarkdownToPdf { + + @PostMapping(consumes = "multipart/form-data", value = "/markdown-to-pdf") + @Operation( + summary = "Convert a Markdown file to PDF", + description = "This endpoint takes a Markdown file input, converts it to HTML, and then to PDF format." + ) + public ResponseEntity markdownToPdf( + @RequestPart(required = true, value = "fileInput") MultipartFile fileInput) + throws IOException, InterruptedException { + + if (fileInput == null) { + throw new IllegalArgumentException("Please provide a Markdown file for conversion."); + } + + String originalFilename = fileInput.getOriginalFilename(); + if (originalFilename == null || !originalFilename.endsWith(".md")) { + throw new IllegalArgumentException("File must be in .md format."); + } + + // Convert Markdown to HTML using CommonMark + Parser parser = Parser.builder().build(); + Node document = parser.parse(new String(fileInput.getBytes())); + HtmlRenderer renderer = HtmlRenderer.builder().build(); + String htmlContent = renderer.render(document); + + byte[] pdfBytes = FileToPdf.convertHtmlToPdf(htmlContent.getBytes(), "converted.html"); + + String outputFilename = originalFilename.replaceFirst("[.][^.]+$", "") + ".pdf"; // Remove file extension and append .pdf + return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java b/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java index 90429f1a3..76e7be8f0 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java @@ -25,7 +25,14 @@ public class ConverterWebController { model.addAttribute("currentPage", "html-to-pdf"); return "convert/html-to-pdf"; } - + @GetMapping("/markdown-to-pdf") + @Hidden + public String convertMarkdownToPdfForm(Model model) { + model.addAttribute("currentPage", "markdown-to-pdf"); + return "convert/markdown-to-pdf"; + } + + @GetMapping("/url-to-pdf") @Hidden public String convertURLToPdfForm(Model model) { diff --git a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java index 75d67401b..4d6e991a4 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java @@ -97,6 +97,20 @@ public class GeneralWebController { return "pdf-organizer"; } + @GetMapping("/extract-page") + @Hidden + public String extractPages(Model model) { + model.addAttribute("currentPage", "extract-page"); + return "extract-page"; + } + + @GetMapping("/pdf-to-single-page") + @Hidden + public String pdfToSinglePage(Model model) { + model.addAttribute("currentPage", "pdf-to-single-page"); + return "pdf-to-single-page"; + } + @GetMapping("/rotate-pdf") @Hidden public String rotatePdfForm(Model model) { diff --git a/src/main/java/stirling/software/SPDF/utils/FileToPdf.java b/src/main/java/stirling/software/SPDF/utils/FileToPdf.java new file mode 100644 index 000000000..9515a3ac2 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/FileToPdf.java @@ -0,0 +1,95 @@ +package stirling.software.SPDF.utils; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; + +public class FileToPdf { + public static byte[] convertHtmlToPdf(byte[] fileBytes, String fileName) throws IOException, InterruptedException { + + Path tempOutputFile = Files.createTempFile("output_", ".pdf"); + Path tempInputFile = null; + byte[] pdfBytes; + try { + if (fileName.endsWith(".html")) { + tempInputFile = Files.createTempFile("input_", ".html"); + Files.write(tempInputFile, fileBytes); + } else { + tempInputFile = unzipAndGetMainHtml(fileBytes); + } + + List command = new ArrayList<>(); + command.add("weasyprint"); + command.add(tempInputFile.toString()); + command.add(tempOutputFile.toString()); + ProcessExecutorResult returnCode; + if (fileName.endsWith(".zip")) { + returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT) + .runCommandWithOutputHandling(command, tempInputFile.getParent().toFile()); + } else { + + returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT) + .runCommandWithOutputHandling(command); + } + + pdfBytes = Files.readAllBytes(tempOutputFile); + } finally { + // Clean up temporary files + Files.delete(tempOutputFile); + Files.delete(tempInputFile); + + if (fileName.endsWith(".zip")) { + GeneralUtils.deleteDirectory(tempInputFile.getParent()); + } + } + + return pdfBytes; + } + + + private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException { + Path tempDirectory = Files.createTempDirectory("unzipped_"); + try (ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(fileBytes))) { + ZipEntry entry = zipIn.getNextEntry(); + while (entry != null) { + Path filePath = tempDirectory.resolve(entry.getName()); + if (entry.isDirectory()) { + Files.createDirectories(filePath); // Explicitly create the directory structure + } else { + Files.createDirectories(filePath.getParent()); // Create parent directories if they don't exist + Files.copy(zipIn, filePath); + } + zipIn.closeEntry(); + entry = zipIn.getNextEntry(); + } + } + + //search for the main HTML file. + try (Stream walk = Files.walk(tempDirectory)) { + List htmlFiles = walk.filter(file -> file.toString().endsWith(".html")) + .collect(Collectors.toList()); + + if (htmlFiles.isEmpty()) { + throw new IOException("No HTML files found in the unzipped directory."); + } + + // Prioritize 'index.html' if it exists, otherwise use the first .html file + for (Path htmlFile : htmlFiles) { + if (htmlFile.getFileName().toString().equals("index.html")) { + return htmlFile; + } + } + + return htmlFiles.get(0); + } + } +} diff --git a/src/main/java/stirling/software/SPDF/utils/WebResponseUtils.java b/src/main/java/stirling/software/SPDF/utils/WebResponseUtils.java index 59c0b0562..09a395baf 100644 --- a/src/main/java/stirling/software/SPDF/utils/WebResponseUtils.java +++ b/src/main/java/stirling/software/SPDF/utils/WebResponseUtils.java @@ -12,6 +12,9 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; + public class WebResponseUtils { public static ResponseEntity boasToWebResponse(ByteArrayOutputStream baos, String docName) throws IOException { @@ -57,5 +60,19 @@ public class WebResponseUtils { return boasToWebResponse(baos, docName); } + + public static ResponseEntity pdfDocToWebResponse(PdfDocument document, String docName) throws IOException { + + // Open Byte Array and save document to it + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter writer = new PdfWriter(baos); + PdfDocument newDocument = new PdfDocument(writer); + + document.copyPagesTo(1, document.getNumberOfPages(), newDocument); + newDocument.close(); + + return boasToWebResponse(baos, docName); + } + } diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 0d881b65b..807e85817 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -236,6 +236,25 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert +home.MarkdownToPDF.title=Markdown to PDF +home.MarkdownToPDF.desc=Converts any Markdown fileto PDF +MarkdownToPDF.tags=markup,web-content,transformation,convert + + +home.getPdfInfo.title=Get ALL Info on PDF +home.getPdfInfo.desc=Grabs any and all information possible on PDFs +getPdfInfo.tags=infomation,data,stats,statistics + + +home.extractPage.title=Extract page(s) +home.extractPage.desc=Extracts select pages from PDF +extractPage.tags=extract + + +home.PdfToSinglePage.title=PDF to Single Large Page +home.PdfToSinglePage.desc=Merges all PDF pages into one large single page +PdfToSinglePage.tags=single page + ########################### # # # WEB PAGES # diff --git a/src/main/resources/static/images/extract.svg b/src/main/resources/static/images/extract.svg new file mode 100644 index 000000000..d21f03eb6 --- /dev/null +++ b/src/main/resources/static/images/extract.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/main/resources/static/images/info.svg b/src/main/resources/static/images/info.svg new file mode 100644 index 000000000..8f48f86cb --- /dev/null +++ b/src/main/resources/static/images/info.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/static/images/markdown.svg b/src/main/resources/static/images/markdown.svg new file mode 100644 index 000000000..ca5cd597d --- /dev/null +++ b/src/main/resources/static/images/markdown.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/main/resources/static/images/single-page.svg b/src/main/resources/static/images/single-page.svg new file mode 100644 index 000000000..4f57d79b7 --- /dev/null +++ b/src/main/resources/static/images/single-page.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/auto-split-pdf.html b/src/main/resources/templates/auto-split-pdf.html index 4f3045e05..d6f68fe14 100644 --- a/src/main/resources/templates/auto-split-pdf.html +++ b/src/main/resources/templates/auto-split-pdf.html @@ -22,7 +22,7 @@
  • -
    +

    diff --git a/src/main/resources/templates/convert/markdown-to-pdf.html b/src/main/resources/templates/convert/markdown-to-pdf.html new file mode 100644 index 000000000..4637d129e --- /dev/null +++ b/src/main/resources/templates/convert/markdown-to-pdf.html @@ -0,0 +1,30 @@ + + + + + + +
    +
    +
    +

    +
    +
    +
    +

    + +
    +
    + + + +

    +

    +
    +
    +
    +
    +
    +
    + + diff --git a/src/main/resources/templates/extract-page.html b/src/main/resources/templates/extract-page.html new file mode 100644 index 000000000..0a5fb1580 --- /dev/null +++ b/src/main/resources/templates/extract-page.html @@ -0,0 +1,33 @@ + + + + + + + +
    +
    +
    +

    +
    +
    +
    +

    +
    +
    + +
    + + +
    + + +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 8cbb6ca7c..c5c8a0daa 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -84,6 +84,13 @@
    +
    +
    +
    +
    + + +
    diff --git a/src/main/resources/templates/pdf-to-single-page.html b/src/main/resources/templates/pdf-to-single-page.html new file mode 100644 index 000000000..1f5b64c66 --- /dev/null +++ b/src/main/resources/templates/pdf-to-single-page.html @@ -0,0 +1,29 @@ + + + + + + + +
    +
    +
    +

    +
    +
    +
    +

    +
    +

    +
    + +
    +
    +
    +
    + +
    +
    +
    + + \ No newline at end of file From 96f05cd5186394b1633f6902bc8ce485f425f476 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Wed, 2 Aug 2023 22:49:43 +0100 Subject: [PATCH 008/301] get info changes --- .../{PDFExtractor.java => GetInfoOnPDF.java} | 175 +++++++++--------- src/main/resources/messages_en_GB.properties | 2 +- src/main/resources/static/js/fileInput.js | 59 +++--- .../resources/templates/fragments/common.html | 12 +- .../resources/templates/other/compare.html | 4 +- .../templates/security/get-info-on-pdf.html | 100 +++++++++- 6 files changed, 226 insertions(+), 126 deletions(-) rename src/main/java/stirling/software/SPDF/controller/api/security/{PDFExtractor.java => GetInfoOnPDF.java} (89%) diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java b/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java similarity index 89% rename from src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java rename to src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java index 2cd429b48..a167cb74b 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/PDFExtractor.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java @@ -73,7 +73,7 @@ import java.util.Set; import java.util.HashSet; @RestController @Tag(name = "Security", description = "Security APIs") -public class PDFExtractor { +public class GetInfoOnPDF { static ObjectMapper objectMapper = new ObjectMapper(); @@ -94,6 +94,13 @@ public class PDFExtractor { // Metadata using PDFBox PDDocumentInformation info = pdfBoxDoc.getDocumentInformation(); ObjectNode metadata = objectMapper.createObjectNode(); + ObjectNode basicInfo = objectMapper.createObjectNode(); + ObjectNode docInfoNode = objectMapper.createObjectNode(); + ObjectNode compliancy = objectMapper.createObjectNode(); + ObjectNode encryption = objectMapper.createObjectNode(); + ObjectNode other = objectMapper.createObjectNode(); + + metadata.put("Title", info.getTitle()); metadata.put("Author", info.getAuthor()); metadata.put("Subject", info.getSubject()); @@ -102,25 +109,25 @@ public class PDFExtractor { metadata.put("Creator", info.getCreator()); metadata.put("CreationDate", formatDate(info.getCreationDate())); metadata.put("ModificationDate", formatDate(info.getModificationDate())); - metadata.put("Trapped", info.getTrapped()); jsonOutput.set("Metadata", metadata); - + + // Total file size of the PDF long fileSizeInBytes = inputFile.getSize(); - jsonOutput.put("FileSizeInBytes", fileSizeInBytes); + basicInfo.put("FileSizeInBytes", fileSizeInBytes); // Number of words, paragraphs, and images in the entire document String fullText = new PDFTextStripper().getText(pdfBoxDoc); String[] words = fullText.split("\\s+"); int wordCount = words.length; int paragraphCount = fullText.split("\r\n|\r|\n").length; - jsonOutput.put("WordCount", wordCount); - jsonOutput.put("ParagraphCount", paragraphCount); + basicInfo.put("WordCount", wordCount); + basicInfo.put("ParagraphCount", paragraphCount); // Number of characters in the entire document (including spaces and special characters) int charCount = fullText.length(); - jsonOutput.put("CharacterCount", charCount); + basicInfo.put("CharacterCount", charCount); // Initialize the flags and types @@ -142,22 +149,24 @@ public class PDFExtractor { hasCompression = true; compressionType = "Compressed Xref or Rebuilt Xref"; } - jsonOutput.put("Compression", hasCompression); + basicInfo.put("Compression", hasCompression); if(hasCompression) - jsonOutput.put("CompressionType", compressionType); + basicInfo.put("CompressionType", compressionType); String language = pdfBoxDoc.getDocumentCatalog().getLanguage(); - jsonOutput.put("Language", language); + basicInfo.put("Language", language); + basicInfo.put("Number of pages", pdfBoxDoc.getNumberOfPages()); - // Document Information using PDFBox - ObjectNode docInfoNode = objectMapper.createObjectNode(); - docInfoNode.put("Number of pages", pdfBoxDoc.getNumberOfPages()); - docInfoNode.put("PDF version", pdfBoxDoc.getVersion()); - // Page Mode using iText7 PdfCatalog catalog = itextDoc.getCatalog(); PdfName pageMode = catalog.getPdfObject().getAsName(PdfName.PageMode); + + // Document Information using PDFBox + docInfoNode.put("PDF version", pdfBoxDoc.getVersion()); + docInfoNode.put("Trapped", info.getTrapped()); + docInfoNode.put("Page Mode", getPageModeDescription(pageMode));; + @@ -193,7 +202,7 @@ public class PDFExtractor { } } - jsonOutput.set("EmbeddedFiles", embeddedFilesArray); + other.set("EmbeddedFiles", embeddedFilesArray); //attachments TODO size ArrayNode attachmentsArray = objectMapper.createArrayNode(); @@ -207,7 +216,7 @@ public class PDFExtractor { } } } - jsonOutput.set("Attachments", attachmentsArray); + other.set("Attachments", attachmentsArray); //Javascript PdfDictionary namesDict = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names); @@ -226,7 +235,7 @@ public class PDFExtractor { } } - jsonOutput.set("JavaScript", javascriptArray); + other.set("JavaScript", javascriptArray); //TODO size PdfOCProperties ocProperties = itextDoc.getCatalog().getOCProperties(false); @@ -240,7 +249,7 @@ public class PDFExtractor { } } - jsonOutput.set("Layers", layersArray); + other.set("Layers", layersArray); //TODO Security @@ -267,7 +276,7 @@ public class PDFExtractor { } } - jsonOutput.set("FormFields", formFieldsArray2); + jsonOutput.set("FormFields2", formFieldsArray2); PDStructureTreeRoot structureTreeRoot = pdfBoxDoc.getDocumentCatalog().getStructureTreeRoot(); @@ -275,19 +284,13 @@ public class PDFExtractor { try { if(structureTreeRoot != null) { structureTreeArray = exploreStructureTree(structureTreeRoot.getKids()); - jsonOutput.set("StructureTree", structureTreeArray); + other.set("StructureTree", structureTreeArray); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - - - - - - boolean isPdfACompliant = checkOutputIntent(itextDoc, "PDF/A"); boolean isPdfXCompliant = checkOutputIntent(itextDoc, "PDF/X"); @@ -297,7 +300,6 @@ public class PDFExtractor { boolean isPdfBCompliant = checkForStandard(itextDoc, "PDF/B"); // If you want to check for PDF/Broadcast, though this isn't an official ISO standard. boolean isPdfSECCompliant = checkForStandard(itextDoc, "PDF/SEC"); // This might not be effective since PDF/SEC was under development in 2021. - ObjectNode compliancy = objectMapper.createObjectNode(); compliancy.put("IsPDF/ACompliant", isPdfACompliant); compliancy.put("IsPDF/XCompliant", isPdfXCompliant); compliancy.put("IsPDF/ECompliant", isPdfECompliant); @@ -306,7 +308,6 @@ public class PDFExtractor { compliancy.put("IsPDF/BCompliant", isPdfBCompliant); compliancy.put("IsPDF/SECCompliant", isPdfSECCompliant); - jsonOutput.set("Compliancy", compliancy); @@ -318,7 +319,7 @@ public class PDFExtractor { addOutlinesToArray(child, bookmarksArray); } } - jsonOutput.set("Bookmarks/Outline/TOC", bookmarksArray); + other.set("Bookmarks/Outline/TOC", bookmarksArray); String xmpString = null; try { @@ -331,29 +332,27 @@ public class PDFExtractor { } catch (XMPException e) { e.printStackTrace(); } - jsonOutput.put("XMPMetadata", xmpString); + other.put("XMPMetadata", xmpString); - ObjectNode encryptionNode = objectMapper.createObjectNode(); if (pdfBoxDoc.isEncrypted()) { - encryptionNode.put("IsEncrypted", true); + encryption.put("IsEncrypted", true); // Retrieve encryption details using getEncryption() - PDEncryption encryption = pdfBoxDoc.getEncryption(); - encryptionNode.put("EncryptionAlgorithm", encryption.getFilter()); - encryptionNode.put("KeyLength", encryption.getLength()); - encryptionNode.put("Permissions", pdfBoxDoc.getCurrentAccessPermission().toString()); + PDEncryption pdfEncryption = pdfBoxDoc.getEncryption(); + encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter()); + encryption.put("KeyLength", pdfEncryption.getLength()); + encryption.put("Permissions", pdfBoxDoc.getCurrentAccessPermission().toString()); // Add other encryption-related properties as needed } else { - encryptionNode.put("IsEncrypted", false); + encryption.put("IsEncrypted", false); } - jsonOutput.set("Encryption", encryptionNode); - docInfoNode.put("Page Mode", getPageModeDescription(pageMode));; + + - jsonOutput.set("Document Information", docInfoNode); ObjectNode pageInfoParent = objectMapper.createObjectNode(); for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) { ObjectNode pageInfo = objectMapper.createObjectNode(); @@ -382,7 +381,6 @@ public class PDFExtractor { pageInfo.put("Text Characters Count", pageText.length()); // // Annotations - ArrayNode annotationsArray = objectMapper.createArrayNode(); List annotations = itextDoc.getPage(pageNum).getAnnotations(); int subtypeCount = 0; @@ -447,61 +445,57 @@ public class PDFExtractor { } pageInfo.set("Links", linksArray); - //Fonts + // Fonts ArrayNode fontsArray = objectMapper.createArrayNode(); PdfDictionary fontDicts = resources.getResource(PdfName.Font); - Set uniqueSubtypes = new HashSet<>(); // To store unique subtypes + Set uniqueSubtypes = new HashSet<>(); // To store unique subtypes + + // Map to store unique fonts and their counts + Map uniqueFontsMap = new HashMap<>(); - if (fontDicts != null) { for (PdfName key : fontDicts.keySet()) { - ObjectNode fontNode = objectMapper.createObjectNode(); // Create a new font node for each font + ObjectNode fontNode = objectMapper.createObjectNode(); // Create a new font node for each font PdfDictionary font = fontDicts.getAsDictionary(key); - - boolean isEmbedded = font.containsKey(PdfName.FontFile) || - font.containsKey(PdfName.FontFile2) || + + boolean isEmbedded = font.containsKey(PdfName.FontFile) || + font.containsKey(PdfName.FontFile2) || font.containsKey(PdfName.FontFile3); - fontNode.put("IsEmbedded", isEmbedded); - - - if (font.containsKey(PdfName.Encoding)) { - String encoding = font.getAsName(PdfName.Encoding).toString(); - fontNode.put("Encoding", encoding); - } - - - - if(font.getAsString(PdfName.BaseFont) != null) + fontNode.put("IsEmbedded", isEmbedded); + + if (font.containsKey(PdfName.Encoding)) { + String encoding = font.getAsName(PdfName.Encoding).toString(); + fontNode.put("Encoding", encoding); + } + + if (font.getAsString(PdfName.BaseFont) != null) { fontNode.put("Name", font.getAsString(PdfName.BaseFont).toString()); - + } + String subtype = null; - // Font Subtype (e.g., Type1, TrueType) if (font.containsKey(PdfName.Subtype)) { subtype = font.getAsName(PdfName.Subtype).toString(); uniqueSubtypes.add(subtype); // Add to set to ensure uniqueness } fontNode.put("Subtype", subtype); - - // Font Descriptor + PdfDictionary fontDescriptor = font.getAsDictionary(PdfName.FontDescriptor); if (fontDescriptor != null) { - // Italic Angle if (fontDescriptor.containsKey(PdfName.ItalicAngle)) { fontNode.put("ItalicAngle", fontDescriptor.getAsNumber(PdfName.ItalicAngle).floatValue()); } - - // Flags (e.g., italic, bold) + if (fontDescriptor.containsKey(PdfName.Flags)) { int flags = fontDescriptor.getAsNumber(PdfName.Flags).intValue(); - fontNode.put("IsItalic", (flags & 64) != 0); // Existing italic flag - fontNode.put("IsBold", (flags & 1 << 16) != 0); // Existing bold flag + fontNode.put("IsItalic", (flags & 64) != 0); + fontNode.put("IsBold", (flags & 1 << 16) != 0); fontNode.put("IsFixedPitch", (flags & 1) != 0); fontNode.put("IsSerif", (flags & 2) != 0); fontNode.put("IsSymbolic", (flags & 4) != 0); fontNode.put("IsScript", (flags & 8) != 0); fontNode.put("IsNonsymbolic", (flags & 16) != 0); } - + if (fontDescriptor.containsKey(PdfName.FontFamily)) { String fontFamily = fontDescriptor.getAsString(PdfName.FontFamily).toString(); fontNode.put("FontFamily", fontFamily); @@ -511,34 +505,43 @@ public class PDFExtractor { String fontStretch = fontDescriptor.getAsName(PdfName.FontStretch).toString(); fontNode.put("FontStretch", fontStretch); } - - if (fontDescriptor != null && fontDescriptor.containsKey(PdfName.FontBBox)) { + + if (fontDescriptor.containsKey(PdfName.FontBBox)) { PdfArray bbox = fontDescriptor.getAsArray(PdfName.FontBBox); fontNode.put("FontBoundingBox", bbox.toString()); } - if (fontDescriptor != null && fontDescriptor.containsKey(PdfName.FontWeight)) { + + if (fontDescriptor.containsKey(PdfName.FontWeight)) { float fontWeight = fontDescriptor.getAsNumber(PdfName.FontWeight).floatValue(); fontNode.put("FontWeight", fontWeight); } - } + if (font.containsKey(PdfName.ToUnicode)) { - PdfStream toUnicodeStream = font.getAsStream(PdfName.ToUnicode); - // Handle the stream as needed, maybe extract some details or just note its existence fontNode.put("HasToUnicodeMap", true); } + if (fontNode.size() > 0) { - fontsArray.add(fontNode); // Add each font node to fontsArray + // Create a unique key for this font node based on its attributes + String uniqueKey = fontNode.toString(); + + // Increment count if this font exists, or initialize it if new + if (uniqueFontsMap.containsKey(uniqueKey)) { + ObjectNode existingFontNode = uniqueFontsMap.get(uniqueKey); + int count = existingFontNode.get("Count").asInt() + 1; + existingFontNode.put("Count", count); + } else { + fontNode.put("Count", 1); + uniqueFontsMap.put(uniqueKey, fontNode); + } } } } - // Add unique subtypes to fontsArray - ArrayNode subtypesArray = objectMapper.createArrayNode(); - for (String subtype : uniqueSubtypes) { - subtypesArray.add(subtype); + // Add unique font entries to fontsArray + for (ObjectNode uniqueFontNode : uniqueFontsMap.values()) { + fontsArray.add(uniqueFontNode); } - pageInfo.set("FontSubtypes", subtypesArray); // Changed from Fonts to FontSubtypes pageInfo.set("Fonts", fontsArray); @@ -605,8 +608,14 @@ public class PDFExtractor { pageInfoParent.set("Page " + pageNum, pageInfo); } + - jsonOutput.set("Per Page Info", pageInfoParent); + jsonOutput.set("BasicInfo", basicInfo); + jsonOutput.set("DocumentInfo", docInfoNode); + jsonOutput.set("Compliancy", compliancy); + jsonOutput.set("Encryption", encryption); + jsonOutput.set("Other", other); + jsonOutput.set("PerPageInfo", pageInfoParent); diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 807e85817..5ae0c5a0a 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -237,7 +237,7 @@ HTMLToPDF.tags=markup,web-content,transformation,convert home.MarkdownToPDF.title=Markdown to PDF -home.MarkdownToPDF.desc=Converts any Markdown fileto PDF +home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert diff --git a/src/main/resources/static/js/fileInput.js b/src/main/resources/static/js/fileInput.js index 94b5294f4..0842462e1 100644 --- a/src/main/resources/static/js/fileInput.js +++ b/src/main/resources/static/js/fileInput.js @@ -1,12 +1,18 @@ document.addEventListener('DOMContentLoaded', function() { + document.querySelectorAll('.custom-file-chooser').forEach(setupFileInput); +}); +function setupFileInput(chooser) { + const elementId = chooser.getAttribute('data-element-id'); + const filesSelected = chooser.getAttribute('data-files-selected'); + const pdfPrompt = chooser.getAttribute('data-pdf-prompt'); + let overlay; let dragCounter = 0; const dragenterListener = function() { dragCounter++; if (!overlay) { - // Create and show the overlay overlay = document.createElement('div'); overlay.style.position = 'fixed'; overlay.style.top = 0; @@ -28,7 +34,6 @@ document.addEventListener('DOMContentLoaded', function() { const dragleaveListener = function() { dragCounter--; if (dragCounter === 0) { - // Hide and remove the overlay if (overlay) { overlay.remove(); overlay = null; @@ -40,24 +45,19 @@ document.addEventListener('DOMContentLoaded', function() { const dt = e.dataTransfer; const files = dt.files; - // Access the file input element and assign dropped files - const fileInput = document.getElementById(elementID); + const fileInput = document.getElementById(elementId); fileInput.files = files; - // Hide and remove the overlay if (overlay) { overlay.remove(); overlay = null; } - // Reset drag counter dragCounter = 0; - //handleFileInputChange(fileInput); fileInput.dispatchEvent(new Event('change', { bubbles: true })); }; - // Prevent default behavior for drag events ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { document.body.addEventListener(eventName, preventDefaults, false); }); @@ -69,29 +69,26 @@ document.addEventListener('DOMContentLoaded', function() { document.body.addEventListener('dragenter', dragenterListener); document.body.addEventListener('dragleave', dragleaveListener); - // Add drop event listener document.body.addEventListener('drop', dropListener); -}); + $("#" + elementId).on("change", function() { + handleFileInputChange(this); + }); -$("#"+elementID).on("change", function() { - handleFileInputChange(this); -}); - - -function handleFileInputChange(inputElement) { - const files = $(inputElement).get(0).files; - const fileNames = Array.from(files).map(f => f.name); - const selectedFilesContainer = $(inputElement).siblings(".selected-files"); - selectedFilesContainer.empty(); - fileNames.forEach(fileName => { - selectedFilesContainer.append("
    " + fileName + "
    "); - }); - if (fileNames.length === 1) { - $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]); - } else if (fileNames.length > 1) { - $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " " + filesSelected); - } else { - $(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt); - } -} \ No newline at end of file + function handleFileInputChange(inputElement) { + const files = $(inputElement).get(0).files; + const fileNames = Array.from(files).map(f => f.name); + const selectedFilesContainer = $(inputElement).siblings(".selected-files"); + selectedFilesContainer.empty(); + fileNames.forEach(fileName => { + selectedFilesContainer.append("
    " + fileName + "
    "); + }); + if (fileNames.length === 1) { + $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]); + } else if (fileNames.length > 1) { + $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " " + filesSelected); + } else { + $(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt); + } + } +} diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index eb0791663..424771130 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -98,7 +98,10 @@ -
    +
    @@ -114,12 +117,7 @@
    - - + diff --git a/src/main/resources/templates/other/compare.html b/src/main/resources/templates/other/compare.html index 7c06062a4..aeb83aee1 100644 --- a/src/main/resources/templates/other/compare.html +++ b/src/main/resources/templates/other/compare.html @@ -15,8 +15,8 @@

    -
    -
    +
    +
    diff --git a/src/main/resources/templates/security/get-info-on-pdf.html b/src/main/resources/templates/security/get-info-on-pdf.html index 36a0bb6e9..dc93186c2 100644 --- a/src/main/resources/templates/security/get-info-on-pdf.html +++ b/src/main/resources/templates/security/get-info-on-pdf.html @@ -15,13 +15,109 @@

    -

    -
    + +

    +
    + +
    + +
    + + + Download JSON +
    +
    From b07437dbfa6907179917b505a6fcbe020fa88a97 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Wed, 2 Aug 2023 23:03:35 +0100 Subject: [PATCH 009/301] get info DONE! --- .../controller/api/security/GetInfoOnPDF.java | 18 +---------------- .../templates/security/get-info-on-pdf.html | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java b/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java index a167cb74b..fea577648 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java @@ -260,23 +260,7 @@ public class GetInfoOnPDF { // Digital Signatures using iText7 TODO - - - - PDAcroForm pdAcroForm = pdfBoxDoc.getDocumentCatalog().getAcroForm(); - ArrayNode formFieldsArray2 = objectMapper.createArrayNode(); - if (pdAcroForm != null) { - - for (PDField field : pdAcroForm.getFields()) { - ObjectNode fieldNode = objectMapper.createObjectNode(); - fieldNode.put("FieldName", field.getFullyQualifiedName()); - fieldNode.put("FieldType", field.getFieldType()); - // Add more attributes as needed... - formFieldsArray2.add(fieldNode); - } - - } - jsonOutput.set("FormFields2", formFieldsArray2); + PDStructureTreeRoot structureTreeRoot = pdfBoxDoc.getDocumentCatalog().getStructureTreeRoot(); diff --git a/src/main/resources/templates/security/get-info-on-pdf.html b/src/main/resources/templates/security/get-info-on-pdf.html index dc93186c2..a77b5ae67 100644 --- a/src/main/resources/templates/security/get-info-on-pdf.html +++ b/src/main/resources/templates/security/get-info-on-pdf.html @@ -5,7 +5,6 @@ -
    @@ -71,14 +70,17 @@ function renderJsonSection(key, value, depth = 0) { + // Replace spaces and other non-alphanumeric characters with underscores for valid IDs + let safeKey = (typeof key === "string") ? key.replace(/[^a-zA-Z0-9]/g, '_') : key; + let output = `
    -
    +
    `; // Check if the value is an object and has children - if (value && typeof value === 'object' && Object.keys(value).length) { + if (value && typeof value === 'object' && (Object.keys(value).length || Array.isArray(value))) { output += ` - `; } else { @@ -89,7 +91,7 @@ output += `
    -
    `; +
    `; // Check if the value is a nested object if (typeof value === 'object' && !Array.isArray(value)) { @@ -99,9 +101,13 @@ } output += '
    '; } else if (typeof value === 'object' && Array.isArray(value) && value.length) { // Array values + output += '
    '; value.forEach((val, index) => { - output += renderJsonSection(index, val, depth + 1); + // For arrays, we're going to make the displayed key more descriptive. + const arrayKey = `${key}[${index}]`; + output += renderJsonSection(arrayKey, val, depth + 1); }); + output += '
    '; } output += '
    '; @@ -109,6 +115,8 @@ return output; } + + From 724fb4bf8fbce5958580ddff1e820a355f7b9019 Mon Sep 17 00:00:00 2001 From: jordy Date: Sat, 5 Aug 2023 17:36:05 +0200 Subject: [PATCH 010/301] add fileInput widget to multiSelect --- .../static/js/multitool/PdfContainer.js | 22 +++--- .../static/js/multitool/fileInput.js | 69 +++++++++++++++++++ src/main/resources/templates/multi-tool.html | 5 +- 3 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/static/js/multitool/fileInput.js diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js index bd150ac6a..45c92be10 100644 --- a/src/main/resources/static/js/multitool/PdfContainer.js +++ b/src/main/resources/static/js/multitool/PdfContainer.js @@ -10,6 +10,7 @@ class PdfContainer { this.pagesContainerWrapper = document.getElementById(wrapperId); this.movePageTo = this.movePageTo.bind(this); this.addPdfs = this.addPdfs.bind(this); + this.addPdfsFromFiles = this.addPdfsFromFiles.bind(this); this.rotateElement = this.rotateElement.bind(this); this.rotateAll = this.rotateAll.bind(this); this.exportPdf = this.exportPdf.bind(this); @@ -57,22 +58,25 @@ class PdfContainer { input.type = 'file'; input.multiple = true; input.setAttribute("accept", "application/pdf"); - input.onchange = async(e) => { const files = e.target.files; - this.fileName = files[0].name; - for (var i=0; i < files.length; i++) { - await this.addPdfFile(files[i], nextSiblingElement); - } - - document.querySelectorAll(".enable-on-file").forEach(element => { - element.disabled = false; - }); + this.addPdfsFromFiles(files, nextSiblingElement); } input.click(); } + async addPdfsFromFiles(files, nextSiblingElement) { + this.fileName = files[0].name; + for (var i=0; i < files.length; i++) { + await this.addPdfFile(files[i], nextSiblingElement); + } + + document.querySelectorAll(".enable-on-file").forEach(element => { + element.disabled = false; + }); + } + rotateElement(element, deg) { var lastTransform = element.style.rotate; if (!lastTransform) { diff --git a/src/main/resources/static/js/multitool/fileInput.js b/src/main/resources/static/js/multitool/fileInput.js new file mode 100644 index 000000000..1a76bd481 --- /dev/null +++ b/src/main/resources/static/js/multitool/fileInput.js @@ -0,0 +1,69 @@ +const addFileDragListener = (callback) => { + let overlay; + let dragCounter = 0; + + const dragenterListener = function() { + dragCounter++; + if (!overlay) { + // Create and show the overlay + overlay = document.createElement('div'); + overlay.style.position = 'fixed'; + overlay.style.top = 0; + overlay.style.left = 0; + overlay.style.width = '100%'; + overlay.style.height = '100%'; + overlay.style.background = 'rgba(0, 0, 0, 0.5)'; + overlay.style.color = '#fff'; + overlay.style.zIndex = '1000'; + overlay.style.display = 'flex'; + overlay.style.alignItems = 'center'; + overlay.style.justifyContent = 'center'; + overlay.style.pointerEvents = 'none'; + overlay.innerHTML = '

    Drop files anywhere to upload

    '; + document.getElementById('content-wrap').appendChild(overlay); + } + }; + + const dragleaveListener = function() { + dragCounter--; + if (dragCounter === 0) { + // Hide and remove the overlay + if (overlay) { + overlay.remove(); + overlay = null; + } + } + }; + + const dropListener = function(e) { + + const dt = e.dataTransfer; + const files = dt.files; + callback(files).catch((err) => { + console.error(err); + //maybe + }).finally(() => { + if (overlay) { + overlay.remove(); + overlay = null; + } + }); + }; + + // Prevent default behavior for drag events + ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { + document.body.addEventListener(eventName, preventDefaults, false); + }); + + function preventDefaults(e) { + e.preventDefault(); + e.stopPropagation(); + } + + document.body.addEventListener('dragenter', dragenterListener); + document.body.addEventListener('dragleave', dragleaveListener); + // Add drop event listener + document.body.addEventListener('drop', dropListener); +} + +export default addFileDragListener; \ No newline at end of file diff --git a/src/main/resources/templates/multi-tool.html b/src/main/resources/templates/multi-tool.html index 50fadcca1..0b1d7b8ac 100644 --- a/src/main/resources/templates/multi-tool.html +++ b/src/main/resources/templates/multi-tool.html @@ -65,7 +65,7 @@ import scrollDivHorizontally from "./js/multitool/horizontalScroll.js"; import ImageHighlighter from "./js/multitool/ImageHighlighter.js"; import PdfActionsManager from './js/multitool/PdfActionsManager.js'; - + import addFileInputListener from './js/multitool/fileInput.js'; // enables drag and drop const dragDropManager = new DragDropManager('drag-container', 'pages-container'); // enables image highlight on click @@ -86,6 +86,9 @@ pdfActionsManager, ] ) + addFileInputListener(async (files) => { + pdfContainer.addPdfsFromFiles(files); + }); + +
    +
    +
    + +
    +
    + + + \ No newline at end of file diff --git a/src/main/resources/templates/security/get-info-on-pdf.html b/src/main/resources/templates/security/get-info-on-pdf.html index 193056e40..06cc10522 100644 --- a/src/main/resources/templates/security/get-info-on-pdf.html +++ b/src/main/resources/templates/security/get-info-on-pdf.html @@ -73,46 +73,45 @@ function renderJsonSection(key, value, depth = 0) { - // Replace spaces and other non-alphanumeric characters with underscores for valid IDs let safeKey = (typeof key === "string") ? key.replace(/[^a-zA-Z0-9]/g, '_') : key; let output = `
    `; - // Check if the value is an object and has children - if (value && typeof value === 'object') { - // For arrays and non-array objects - if (Array.isArray(value) && value.length === 0) { - output += `${key}: Empty array`; - } else if (!Array.isArray(value) && Object.keys(value).length === 0) { - output += `${key}: Empty object`; - } else { - output += ` - `; - } - } else { - // For simple key-value pairs - output += `${key}: ${value}`; - } - + if (key === 'XMPMetadata' && typeof value === "string") { + output += ``; + } else if (value && typeof value === 'object') { + if (Array.isArray(value) && value.length === 0) { + output += `${key}: Empty array`; + } else if (!Array.isArray(value) && Object.keys(value).length === 0) { + output += `${key}: Empty object`; + } else { + output += ``; + } + } else { + output += `${key}: ${value}`; + } output += ` -
    -
    -
    `; + +
    +
    `; - // Check if the value is a nested object - if (value && typeof value === 'object' && !Array.isArray(value)) { + if (key === 'XMPMetadata' && typeof value === "string") { + output += `
    ${escapeHTML(value)}
    `; + } else if (value && typeof value === 'object' && !Array.isArray(value)) { output += '
    '; if (Object.keys(value).length) { for (const subKey in value) { output += renderJsonSection(subKey, value[subKey], depth + 1); } } else { - output += '

    Empty object

    '; + output += '

    Empty

    '; } output += '
    '; } else if (value && typeof value === 'object' && Array.isArray(value)) { @@ -123,7 +122,7 @@ output += renderJsonSection(arrayKey, val, depth + 1); }); } else { - output += '

    Empty array

    '; + output += '

    Empty

    '; } output += '
    '; } @@ -132,6 +131,14 @@ return output; } + + + function escapeHTML(s) { + if(s) + return s.replace(/&/g, '&').replace(//g, '>'); + + return null; + }
    From 5d3ee7755a5387d3bbe594d3f04b567549f54605 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 6 Aug 2023 21:57:35 +0100 Subject: [PATCH 017/301] show js --- src/main/resources/messages_ar_AR.properties | 41 ++++++++------------ src/main/resources/messages_ca_CA.properties | 41 ++++++++------------ src/main/resources/messages_de_DE.properties | 41 ++++++++------------ src/main/resources/messages_es_ES.properties | 41 ++++++++------------ src/main/resources/messages_eu_ES.properties | 41 ++++++++------------ src/main/resources/messages_fr_FR.properties | 41 ++++++++------------ src/main/resources/messages_it_IT.properties | 41 ++++++++------------ src/main/resources/messages_ja_JP.properties | 41 ++++++++------------ src/main/resources/messages_ko_KR.properties | 41 ++++++++------------ src/main/resources/messages_pl_PL.properties | 41 ++++++++------------ src/main/resources/messages_pt_BR.properties | 41 ++++++++------------ src/main/resources/messages_ro_RO.properties | 41 ++++++++------------ src/main/resources/messages_ru_RU.properties | 41 ++++++++------------ src/main/resources/messages_sv_SE.properties | 41 ++++++++------------ src/main/resources/messages_zh_CN.properties | 41 ++++++++------------ 15 files changed, 240 insertions(+), 375 deletions(-) diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index 9ec04294a..53a0fa448 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties index 938a6f2ae..6d653a9b7 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties index d36cc592d..1b5691bf4 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index b7721482b..6f31beeca 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Convierte cualquier archivo HTML o ZIP a PDF HTMLToPDF.tags=margen,contenido web,transformación,convertir -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties index 817df5193..c1e6eba0c 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index cc93ca809..b26278f59 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index 4f8ecb273..4e5cf304a 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index 3a7d2c066..4e49c578c 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index 88e311db9..4c5a1e8c8 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index 82de60dd1..2e04e80aa 100644 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index af8517167..e615c7304 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties index 0e2a1602b..11a5c090c 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties index f64c0c59a..89be5d643 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties index 6687fcf6d..06637e862 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties index 0c557eb7b..7ece8479d 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -236,67 +236,61 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF HTMLToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.MarkdownToPDF.title=Markdown to PDF home.MarkdownToPDF.desc=Converts any Markdown file to PDF MarkdownToPDF.tags=markup,web-content,transformation,convert -########################## -### TODO: Translate ### -########################## home.getPdfInfo.title=Get ALL Info on PDF home.getPdfInfo.desc=Grabs any and all information possible on PDFs getPdfInfo.tags=infomation,data,stats,statistics -########################## -### TODO: Translate ### -########################## home.extractPage.title=Extract page(s) home.extractPage.desc=Extracts select pages from PDF extractPage.tags=extract -########################## -### TODO: Translate ### -########################## home.PdfToSinglePage.title=PDF to Single Large Page home.PdfToSinglePage.desc=Merges all PDF pages into one large single page PdfToSinglePage.tags=single page + +########################## +### TODO: Translate ### +########################## +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + ########################### # # # WEB PAGES # # # ########################### - - - -#pdfToSinglePage +#showJS ########################## ### TODO: Translate ### ########################## +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage pdfToSinglePage.title=PDF To Single Page pdfToSinglePage.header=PDF To Single Page pdfToSinglePage.submit=Convert To Single Page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract #getPdfInfo -########################## -### TODO: Translate ### -########################## getPdfInfo.title=Get Info on PDF getPdfInfo.header=Get Info on PDF getPdfInfo.submit=Get Info @@ -304,9 +298,6 @@ getPdfInfo.downloadJson=Download JSON #markdown-to-pdf -########################## -### TODO: Translate ### -########################## MarkdownToPDF.title=Markdown To PDF MarkdownToPDF.header=Markdown To PDF MarkdownToPDF.submit=Convert From 9cb4d8e088e09b7b53364f4e2b5c7c04513c4764 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 6 Aug 2023 21:58:55 +0100 Subject: [PATCH 018/301] remove copy fonts from LITE --- Dockerfile-lite | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Dockerfile-lite b/Dockerfile-lite index eb92e4879..d3968a2ad 100644 --- a/Dockerfile-lite +++ b/Dockerfile-lite @@ -10,12 +10,6 @@ RUN apt-get update && \ unoconv && \ rm -rf /var/lib/apt/lists/* -#Install fonts -RUN mkdir /usr/share/fonts/opentype/noto/ -COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/ -COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/ -RUN fc-cache -f -v - # Copy the application JAR file COPY build/libs/*.jar app.jar From 4a579c00cea49dfeb8fc00381265b77668a53c7e Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 6 Aug 2023 22:14:37 +0100 Subject: [PATCH 019/301] docs --- Endpoint-groups.md | 7 ++++++- Version-groups.md | 7 ++++++- .../software/SPDF/config/EndpointConfiguration.java | 13 +++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Endpoint-groups.md b/Endpoint-groups.md index e64013961..9c7f3ae64 100644 --- a/Endpoint-groups.md +++ b/Endpoint-groups.md @@ -3,9 +3,11 @@ | adjust-contrast | ✔️ | | | | | | | | | | ✔️ | | auto-split-pdf | ✔️ | | | | | | | | | ✔️ | | | crop | ✔️ | | | | | | | | | ✔️ | | +| extract-page | ✔️ | | | | | | | | | ✔️ | | | merge-pdfs | ✔️ | | | | | | | | | ✔️ | | | multi-page-layout | ✔️ | | | | | | | | | ✔️ | | | pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ | +| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | | | remove-pages | ✔️ | | | | | | | | | ✔️ | | | rotate-pdf | ✔️ | | | | | | | | | ✔️ | | | scale-pages | ✔️ | | | | | | | | | ✔️ | | @@ -15,6 +17,7 @@ | pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-img | | ✔️ | | | | | | | | ✔️ | | | pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | | +| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | | | pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | | @@ -34,8 +37,10 @@ | compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | extract-images | | | | ✔️ | | | | | | ✔️ | | -| flatten | | | | ✔️ | | | | | | | | +| flatten | | | | ✔️ | | | | | | | ✔️ | +| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | | | ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | repair | | | | ✔️ | ✔️ | | | ✔️ | | | | +| show-javascript | | | | ✔️ | | | | | | | ✔️ | | sign | | | | ✔️ | | | | | | | ✔️ | \ No newline at end of file diff --git a/Version-groups.md b/Version-groups.md index 557cadb28..900205796 100644 --- a/Version-groups.md +++ b/Version-groups.md @@ -15,6 +15,7 @@ Operation | Ultra-Lite | Lite | Full --------------------|------------|------|----- add-page-numbers | ✔️ | ✔️ | ✔️ add-password | ✔️ | ✔️ | ✔️ +add-image | ✔️ | ✔️ | ✔️ add-watermark | ✔️ | ✔️ | ✔️ adjust-contrast | ✔️ | ✔️ | ✔️ auto-split-pdf | ✔️ | ✔️ | ✔️ @@ -24,21 +25,25 @@ crop | ✔️ | ✔️ | ✔️ change-metadata | ✔️ | ✔️ | ✔️ change-permissions | ✔️ | ✔️ | ✔️ compare | ✔️ | ✔️ | ✔️ +extract-page | ✔️ | ✔️ | ✔️ extract-images | ✔️ | ✔️ | ✔️ flatten | ✔️ | ✔️ | ✔️ +get-info-on-pdf | ✔️ | ✔️ | ✔️ img-to-pdf | ✔️ | ✔️ | ✔️ +markdown-to-pdf | ✔️ | ✔️ | ✔️ merge-pdfs | ✔️ | ✔️ | ✔️ multi-page-layout | ✔️ | ✔️ | ✔️ pdf-organizer | ✔️ | ✔️ | ✔️ pdf-to-img | ✔️ | ✔️ | ✔️ +pdf-to-single-page | ✔️ | ✔️ | ✔️ remove-pages | ✔️ | ✔️ | ✔️ remove-password | ✔️ | ✔️ | ✔️ rotate-pdf | ✔️ | ✔️ | ✔️ sanitize-pdf | ✔️ | ✔️ | ✔️ scale-pages | ✔️ | ✔️ | ✔️ sign | ✔️ | ✔️ | ✔️ +show-javascript | ✔️ | ✔️ | ✔️ split-pdfs | ✔️ | ✔️ | ✔️ -add-image | ✔️ | ✔️ | ✔️ file-to-pdf | | ✔️ | ✔️ pdf-to-html | | ✔️ | ✔️ pdf-to-presentation | | ✔️ | ✔️ diff --git a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java index 322de0e2c..11f7b8c8a 100644 --- a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java @@ -71,6 +71,8 @@ public class EndpointConfiguration { addEndpointToGroup("PageOps", "adjust-contrast"); addEndpointToGroup("PageOps", "crop"); addEndpointToGroup("PageOps", "auto-split-pdf"); + addEndpointToGroup("PageOps", "extract-page"); + addEndpointToGroup("PageOps", "pdf-to-single-page"); // Adding endpoints to "Convert" group addEndpointToGroup("Convert", "pdf-to-img"); @@ -85,6 +87,7 @@ public class EndpointConfiguration { addEndpointToGroup("Convert", "pdf-to-xml"); addEndpointToGroup("Convert", "html-to-pdf"); addEndpointToGroup("Convert", "url-to-pdf"); + addEndpointToGroup("Convert", "markdown-to-pdf"); // Adding endpoints to "Security" group addEndpointToGroup("Security", "add-password"); @@ -94,7 +97,7 @@ public class EndpointConfiguration { addEndpointToGroup("Security", "cert-sign"); addEndpointToGroup("Security", "sanitize-pdf"); - + // Adding endpoints to "Other" group addEndpointToGroup("Other", "ocr-pdf"); addEndpointToGroup("Other", "add-image"); @@ -109,7 +112,8 @@ public class EndpointConfiguration { addEndpointToGroup("Other", "compare"); addEndpointToGroup("Other", "add-page-numbers"); addEndpointToGroup("Other", "auto-rename"); - + addEndpointToGroup("Other", "get-info-on-pdf"); + addEndpointToGroup("Other", "show-javascript"); @@ -180,6 +184,11 @@ public class EndpointConfiguration { addEndpointToGroup("Java", "auto-split-pdf"); addEndpointToGroup("Java", "sanitize-pdf"); addEndpointToGroup("Java", "crop"); + addEndpointToGroup("Java", "get-info-on-pdf"); + addEndpointToGroup("Java", "extract-page"); + addEndpointToGroup("Java", "pdf-to-single-page"); + addEndpointToGroup("Java", "markdown-to-pdf"); + addEndpointToGroup("Java", "show-javascript"); //Javascript addEndpointToGroup("Javascript", "pdf-organizer"); From 891f9e225245110b965bf4986dce63f997f124c6 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Tue, 8 Aug 2023 19:55:18 +0100 Subject: [PATCH 020/301] api changes --- README.md | 1 + build.gradle | 2 +- .../controller/web/MetricsController.java | 212 +++++++++++++++--- 3 files changed, 188 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index f88f9873c..9b7365f34 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ Using the same method you can also change - Disable and remove endpoints and functionality from Stirling-PDF. Currently the endpoints ENDPOINTS_TO_REMOVE and GROUPS_TO_REMOVE can include comma seperated lists of endpoints and groups to disable as example ENDPOINTS_TO_REMOVE=img-to-pdf,remove-pages would disable both image to pdf and remove pages, GROUPS_TO_REMOVE=LibreOffice Would disable all things that use LibreOffice. You can see a list of all endpoints and groups [here](https://github.com/Frooodle/Stirling-PDF/blob/main/groups.md) - Change the max file size allowed through the server with the environment variable MAX_FILE_SIZE. default 2000MB - Customise static files such as app logo by placing files in the /customFiles/static/ directory. Example to customise app logo is placing a /customFiles/static/favicon.svg to override current SVG. This can be used to change any images/icons/css/fonts/js etc in Stirling-PDF +- Enable/Disable metric api endpoints with ENABLE_API_METRICS. Default enabled ## API For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation diff --git a/build.gradle b/build.gradle index 832cbc2db..dcc53c3e5 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group = 'stirling.software' -version = '0.12.1' +version = '0.12.2' sourceCompatibility = '17' repositories { diff --git a/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java b/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java index 70235df31..ab18b1b5b 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java @@ -1,8 +1,16 @@ package stirling.software.SPDF.controller.web; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Comparator; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -14,6 +22,8 @@ import io.micrometer.core.instrument.MeterRegistry; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.PostConstruct; +import stirling.software.SPDF.config.StartupApplicationListener; @RestController @RequestMapping("/api/v1") @@ -22,6 +32,20 @@ public class MetricsController { private final MeterRegistry meterRegistry; + private boolean isEndpointEnabled; + + @PostConstruct + public void init() { + String isEndpointEnabled = System.getProperty("ENABLE_API_METRICS"); + if (isEndpointEnabled == null) { + isEndpointEnabled = System.getenv("ENABLE_API_METRICS"); + if (isEndpointEnabled == null) { + isEndpointEnabled = "true"; + } + } + this.isEndpointEnabled = "true".equalsIgnoreCase(isEndpointEnabled); + } + public MetricsController(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } @@ -29,18 +53,25 @@ public class MetricsController { @GetMapping("/status") @Operation(summary = "Application status and version", description = "This endpoint returns the status of the application and its version number.") - public Map getStatus() { + public ResponseEntity getStatus() { + if (!isEndpointEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + Map status = new HashMap<>(); status.put("status", "UP"); status.put("version", getClass().getPackage().getImplementationVersion()); - return status; + return ResponseEntity.ok(status); } @GetMapping("/loads") @Operation(summary = "GET request count", description = "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.") - public Double getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional endpoint) { - try { + public ResponseEntity getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional endpoint) { + if (!isEndpointEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { double count = 0.0; @@ -68,36 +99,165 @@ public class MetricsController { } } - return count; + return ResponseEntity.ok(count); } catch (Exception e) { - return -1.0; + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } + @GetMapping("/loads/all") + @Operation(summary = "GET requests count for all endpoints", + description = "This endpoint returns the count of GET requests for each endpoint.") + public ResponseEntity getAllEndpointLoads() { + if (!isEndpointEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + Map counts = new HashMap<>(); + + for (Meter meter : meterRegistry.getMeters()) { + if (meter.getId().getName().equals("http.requests")) { + String method = meter.getId().getTag("method"); + if (method != null && method.equals("GET")) { + String uri = meter.getId().getTag("uri"); + if (uri != null) { + double currentCount = counts.getOrDefault(uri, 0.0); + if (meter instanceof Counter) { + currentCount += ((Counter) meter).count(); + } + counts.put(uri, currentCount); + } + } + } + } + + List results = counts.entrySet().stream() + .map(entry -> new EndpointCount(entry.getKey(), entry.getValue())) + .sorted(Comparator.comparing(EndpointCount::getCount).reversed()) + .collect(Collectors.toList()); + + return ResponseEntity.ok(results); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + public class EndpointCount { + private String endpoint; + private double count; + + public EndpointCount(String endpoint, double count) { + this.endpoint = endpoint; + this.count = count; + } + public String getEndpoint() { + return endpoint; + } + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + public double getCount() { + return count; + } + public void setCount(double count) { + this.count = count; + } + + } + + @GetMapping("/requests") @Operation(summary = "POST request count", description = "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.") - public Double getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional endpoint) { - try { - Counter counter; - if (endpoint.isPresent() && !endpoint.get().isBlank()) { - if(!endpoint.get().startsWith("/")) { - endpoint = Optional.of("/" + endpoint.get()); - } - - System.out.println("loads " + endpoint.get() + " vs " + meterRegistry.get("http.requests").tags("uri", endpoint.get()).toString()); - counter = meterRegistry.get("http.requests") - .tags("method", "POST", "uri", endpoint.get()).counter(); - } else { - counter = meterRegistry.get("http.requests") - .tags("method", "POST").counter(); - } - return counter.count(); - } catch (Exception e) { - e.printStackTrace(); - return 0.0; + public ResponseEntity getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional endpoint) { + if (!isEndpointEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + double count = 0.0; + + for (Meter meter : meterRegistry.getMeters()) { + if (meter.getId().getName().equals("http.requests")) { + String method = meter.getId().getTag("method"); + if (method != null && method.equals("POST")) { + if (endpoint.isPresent() && !endpoint.get().isBlank()) { + if (!endpoint.get().startsWith("/")) { + endpoint = Optional.of("/" + endpoint.get()); + } + if (endpoint.get().equals(meter.getId().getTag("uri"))) { + if (meter instanceof Counter) { + count += ((Counter) meter).count(); + } + } + } else { + if (meter instanceof Counter) { + count += ((Counter) meter).count(); + } + } + } + } + } + return ResponseEntity.ok(count); + } catch (Exception e) { + return ResponseEntity.ok(-1); } - } + + @GetMapping("/requests/all") + @Operation(summary = "POST requests count for all endpoints", + description = "This endpoint returns the count of POST requests for each endpoint.") + public ResponseEntity getAllPostRequests() { + if (!isEndpointEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + Map counts = new HashMap<>(); + + for (Meter meter : meterRegistry.getMeters()) { + if (meter.getId().getName().equals("http.requests")) { + String method = meter.getId().getTag("method"); + if (method != null && method.equals("POST")) { + String uri = meter.getId().getTag("uri"); + if (uri != null) { + double currentCount = counts.getOrDefault(uri, 0.0); + if (meter instanceof Counter) { + currentCount += ((Counter) meter).count(); + } + counts.put(uri, currentCount); + } + } + } + } + + List results = counts.entrySet().stream() + .map(entry -> new EndpointCount(entry.getKey(), entry.getValue())) + .sorted(Comparator.comparing(EndpointCount::getCount).reversed()) + .collect(Collectors.toList()); + + return ResponseEntity.ok(results); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + + @GetMapping("/uptime") + public ResponseEntity getUptime() { + if (!isEndpointEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + + LocalDateTime now = LocalDateTime.now(); + Duration uptime = Duration.between(StartupApplicationListener.startTime, now); + return ResponseEntity.ok(formatDuration(uptime)); + } + + private String formatDuration(Duration duration) { + long days = duration.toDays(); + long hours = duration.toHoursPart(); + long minutes = duration.toMinutesPart(); + long seconds = duration.toSecondsPart(); + return String.format("%dd %dh %dm %ds", days, hours, minutes, seconds); + } } From d797169bd08ec0d65803e7cabb97085dabec4663 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:56:05 +0000 Subject: [PATCH 021/301] Bump io.spring.dependency-management from 1.1.0 to 1.1.2 Bumps [io.spring.dependency-management](https://github.com/spring-gradle-plugins/dependency-management-plugin) from 1.1.0 to 1.1.2. - [Release notes](https://github.com/spring-gradle-plugins/dependency-management-plugin/releases) - [Commits](https://github.com/spring-gradle-plugins/dependency-management-plugin/compare/v1.1.0...v1.1.2) --- updated-dependencies: - dependency-name: io.spring.dependency-management dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dcc53c3e5..74945e670 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.1.1' - id 'io.spring.dependency-management' version '1.1.0' + id 'io.spring.dependency-management' version '1.1.2' id 'org.springdoc.openapi-gradle-plugin' version '1.6.0' id "io.swagger.swaggerhub" version "1.2.0" id 'edu.sc.seis.launch4j' version '3.0.3' From ca16ecef24ae699197d1455eea51ebe2905be968 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Tue, 8 Aug 2023 20:09:05 +0100 Subject: [PATCH 022/301] Create StartupApplicationListener.java --- .../config/StartupApplicationListener.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/stirling/software/SPDF/config/StartupApplicationListener.java diff --git a/src/main/java/stirling/software/SPDF/config/StartupApplicationListener.java b/src/main/java/stirling/software/SPDF/config/StartupApplicationListener.java new file mode 100644 index 000000000..a25cbbbf5 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/StartupApplicationListener.java @@ -0,0 +1,20 @@ +package stirling.software.SPDF.config; + + +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +@Component +public class StartupApplicationListener implements ApplicationListener { + + public static LocalDateTime startTime; + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + startTime = LocalDateTime.now(); + } +} + From 374a30ac5afa0faf35c836b97cd2f3b7139b790d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 19:20:25 +0000 Subject: [PATCH 023/301] Bump org.springframework.boot from 3.1.1 to 3.1.2 Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.1.1...v3.1.2) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index debc1f9a5..7574b5178 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.1.1' + id 'org.springframework.boot' version '3.1.2' id 'io.spring.dependency-management' version '1.1.0' id 'org.springdoc.openapi-gradle-plugin' version '1.6.0' id "io.swagger.swaggerhub" version "1.2.0" From 2c1412a0885043c9220f1290a2377059337cffa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 19:25:50 +0000 Subject: [PATCH 024/301] Bump org.springframework.boot:spring-boot-starter-web Bumps [org.springframework.boot:spring-boot-starter-web](https://github.com/spring-projects/spring-boot) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.1.0...v3.1.2) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5f8f56472..6f0a0b970 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ launch4j { } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web:3.1.0' + implementation 'org.springframework.boot:spring-boot-starter-web:3.1.2' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.1' testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.0' // https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio From 45845626072073e3471dab1a02371ac37ab07416 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 19:25:51 +0000 Subject: [PATCH 025/301] Bump org.springframework.boot:spring-boot-starter-test Bumps [org.springframework.boot:spring-boot-starter-test](https://github.com/spring-projects/spring-boot) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.1.0...v3.1.2) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5f8f56472..3819f14bd 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ launch4j { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web:3.1.0' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.1' - testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.0' + testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.2' // https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4' implementation 'commons-io:commons-io:2.13.0' From 3420adc7c9e3d155bbc3ef50dbe633c26df25b9b Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Wed, 9 Aug 2023 20:30:07 +0100 Subject: [PATCH 026/301] security and apple icons --- build.gradle | 5 +- .../software/SPDF/config/MetricsFilter.java | 2 +- .../static/android-chrome-192x192.png | Bin 0 -> 20882 bytes .../static/android-chrome-512x512.png | Bin 0 -> 85906 bytes .../static/apple-touch-icon-114x114.png | Bin 0 -> 8410 bytes .../static/apple-touch-icon-120x120.png | Bin 0 -> 8532 bytes .../static/apple-touch-icon-144x144.png | Bin 0 -> 11054 bytes .../static/apple-touch-icon-152x152.png | Bin 0 -> 11691 bytes .../static/apple-touch-icon-180x180.png | Bin 0 -> 14520 bytes .../static/apple-touch-icon-57x57.png | Bin 0 -> 3667 bytes .../static/apple-touch-icon-60x60.png | Bin 0 -> 3922 bytes .../static/apple-touch-icon-72x72.png | Bin 0 -> 4783 bytes .../static/apple-touch-icon-76x76.png | Bin 0 -> 5107 bytes .../resources/static/apple-touch-icon.png | Bin 0 -> 14520 bytes src/main/resources/static/browserconfig.xml | 9 + src/main/resources/static/favicon-16x16.png | Bin 0 -> 1473 bytes src/main/resources/static/favicon-32x32.png | Bin 0 -> 2544 bytes src/main/resources/static/favicon.ico | Bin 205814 -> 15086 bytes src/main/resources/static/manifest.json | 20 ++ src/main/resources/static/mstile-150x150.png | Bin 0 -> 12941 bytes .../resources/static/safari-pinned-tab.svg | 41 ++++ src/main/resources/static/site.webmanifest | 19 ++ .../resources/templates/fragments/common.html | 18 ++ .../templates/other/show-javascript.html | 17 +- .../templates/security/get-info-on-pdf.html | 206 +++++++++--------- 25 files changed, 233 insertions(+), 104 deletions(-) create mode 100644 src/main/resources/static/android-chrome-192x192.png create mode 100644 src/main/resources/static/android-chrome-512x512.png create mode 100644 src/main/resources/static/apple-touch-icon-114x114.png create mode 100644 src/main/resources/static/apple-touch-icon-120x120.png create mode 100644 src/main/resources/static/apple-touch-icon-144x144.png create mode 100644 src/main/resources/static/apple-touch-icon-152x152.png create mode 100644 src/main/resources/static/apple-touch-icon-180x180.png create mode 100644 src/main/resources/static/apple-touch-icon-57x57.png create mode 100644 src/main/resources/static/apple-touch-icon-60x60.png create mode 100644 src/main/resources/static/apple-touch-icon-72x72.png create mode 100644 src/main/resources/static/apple-touch-icon-76x76.png create mode 100644 src/main/resources/static/apple-touch-icon.png create mode 100644 src/main/resources/static/browserconfig.xml create mode 100644 src/main/resources/static/favicon-16x16.png create mode 100644 src/main/resources/static/favicon-32x32.png create mode 100644 src/main/resources/static/manifest.json create mode 100644 src/main/resources/static/mstile-150x150.png create mode 100644 src/main/resources/static/safari-pinned-tab.svg create mode 100644 src/main/resources/static/site.webmanifest diff --git a/build.gradle b/build.gradle index 8f0c72eca..5e95460f4 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group = 'stirling.software' -version = '0.12.2' +version = '0.12.3' sourceCompatibility = '17' repositories { @@ -45,8 +45,9 @@ launch4j { } dependencies { + implementation 'org.yaml:snakeyaml:2.1' implementation 'org.springframework.boot:spring-boot-starter-web:3.1.2' - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.1' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.2' testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.2' // https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4' diff --git a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java index 87edc0f6f..5b8ffd67e 100644 --- a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java +++ b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java @@ -30,7 +30,7 @@ public class MetricsFilter extends OncePerRequestFilter { //System.out.println("uri="+uri + ", method=" + request.getMethod() ); // Ignore static resources - if (!(uri.startsWith("/js") || uri.startsWith("/images") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) { + if (!(uri.startsWith("/js") || uri.startsWith("api-docs") || uri.startsWith("/images") || uri.endsWith(".png") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) { Counter counter = Counter.builder("http.requests") .tag("uri", uri) .tag("method", request.getMethod()) diff --git a/src/main/resources/static/android-chrome-192x192.png b/src/main/resources/static/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..0c199d036662c34e04efd2635268660f2a23fb77 GIT binary patch literal 20882 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 DATzrp literal 0 HcmV?d00001 diff --git a/src/main/resources/static/android-chrome-512x512.png b/src/main/resources/static/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..011e5383b915e6014f943f4a0de0d53ff45de8e3 GIT binary patch literal 85906 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 NP*c(ZS1VXW{6CEW4r>4a literal 0 HcmV?d00001 diff --git a/src/main/resources/static/apple-touch-icon-120x120.png b/src/main/resources/static/apple-touch-icon-120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..20fa214855cf23fa4ee7bbbfff64f145b73615c7 GIT binary patch literal 8532 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 Xgg9=O61>T8CIA^pMM#x|(U<=LPn&F+ literal 0 HcmV?d00001 diff --git a/src/main/resources/static/apple-touch-icon-144x144.png b/src/main/resources/static/apple-touch-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..078bbb447cae51ac00821445c01ed7d7cdb97e09 GIT binary patch literal 11054 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/static/apple-touch-icon-152x152.png b/src/main/resources/static/apple-touch-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..643ac5345ed9a5ad3d6a1b32cfb0e2ccac45dd14 GIT binary patch literal 11691 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/static/apple-touch-icon-180x180.png b/src/main/resources/static/apple-touch-icon-180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..debef0d7429b30497ed834e4b6e6ff366f21f4f8 GIT binary patch literal 14520 zcmb_@V{|1=)b0r;#yPPjIk9cqn%K7OOf<1=PV5OMm?RS$6Wg|poA>^^KklDzeXCbj zt*-8>{nYNlu6k-md{dA_M!-V=0079+Qew)VapQkC9OP$MUz=d|89`eJ%L@Ylb#aKV zMqfUk!6s75@&JH01pp8b3;;ZTCIuV<0B%eGz_B3!z>^LDU^`~FDe-;2fH9Vp6a#$x zcjb4KCVi&Bx=PE7!ydrFBSRum{;LiL064Xz#e`Kom(MypvdJvGE?)R9bmolOD9JFfWhKx*I;W8!iGk1QU`JzMGD4%|hTH zAsk}6WR9`1^V8i~ZZ*%1gLfspIm}WYcMo$mS;6JWveJsuwzhSLx7=HGOf*nqwVly` zx;O0d{dN-vfn8MN|8l@)R_w7U!@(lo5Wg@uptLpI@d9)zez0_!58ZLb0}WfxW#`Q> z=$4`6R_AgT<_MN5D%`F<{N3+(QTM*Uva{o2n4|MzDk-r(2(__L(13-#yK-X9N@#-s z2#Ep6_GB*h`!(@n#qmK()#hW9M}>t=-3@cBr8cCb`(x2mm=SQ{fMdaczfWfD+W4`l z(Q+ynh|jyp?tU%q_i}cYQba_YF1XXTFo^cxSJSF`%iekpf-UpmAKZeqF>%&Eel#^$ zSd$*a9N}s)Bo;mMX8(qq6$US$p%OJ7|5UQ<-Qqwip~8wOr#^daU0!Nfp33K7W~kSi zW@m&$0Wx&Mxsb1`RZjYqZ9Ait|W>9O<{74qi3P%C==t^sz9)0*&|8baGN`Z%kCzcgA@z(Bg)W;{7 z4Gp`!Von%MEb)<;KcnQUSs~P#WaQtq`p+uXrHuI+7WK+$_+qj?lQRnI{j^?-LKOtfH^-rT! zb3GmeIFKw5T63x5CF&~*nn_>F7^P{|V=8$=Ggp-}8CO(f&T9`6O+txrYnvgD~76MWz z-S7FR&cU~R_%}*Cu?7#SpVD8W&j!X?sE6|pX7c~a`%eWW^xi7tdeSFm(fxzDM)rt0 zWr5tLaM-wLQZ<(UzV~lh4)wMg**Sjea$HYumPy(s`Q0K{XQ8@|-${Ow7P1sh*8ALR z0P|Z!tX`L;wB+_5$jbJ1fv3>2q((abb8abeS|7)xzA?dnjbRAF`K1nDg}Vl z6&|c7a13|W;&o|z9rK@!C7PieV3a28vGp=hT%Zi;&+S&5$on!b9|{*w48My>;1X_J z_u7z$(Rt%}HhZI5t^bbNg2CT%O74hYr|F*c+lLVO@a>j3<7`=OKdLGWGQlts32gIKM~(H|mB6g6{z z8Kk?cb5-{b68D^E5bbNvelwZltO7ya3(?1ha)R&{1b~jsJdM;YVm5LAu!UYK6pr`@ zo?}(Eo*!3H$zJC@Wj~*`{rEE72`A7Bq z`cts-v<>w=8Kf0FB&4WuG!7(K>gZW=zD6@**UXVT3MH_k7Cy(cxLHCMpSLf6$0 zbpJE`6l$s}nwT5_++oRxFK;|NW$|ef*Z6&SiV;CpjsQ-Kw>+#;HtUC+H231@ZQxd? zDJVdP05d3_;yz)*!4+Wa2w6+cX$By9V7ZuatYeuah|rT051EE7{hnBCk>2>#t-C_W z!)wMTi~wtT#|+U04glt#{88O*XgFT9Jni{nW{pQ{2CkqC!=4jqPqvOMc0(&5&`l2p{ZL`JPm0UzMP%^%J&cEDzw!hqjp$Pnmxd8#3FO-4=+`2NuRb315*;AmI z8{{=xpw3&5oZ6nAEj;qvQN;qR#vm}=Ta z7VC?>N9m7SxB6TpXSaxFT_;z!`&$#m$4DwiLp%JT!N7`P&1^Wgna^Ig|GO*Oo?N$= zd|0)@d(>_Y-yt>UhzH$JK2_A!NXS$i#2_}*3M*mAJxi*UA!7xLder`)`hK?I<9}&d zS~1e!IK@ztWKo?8hz|Ir@LOyuiCG*igCsGU)>%LjJt~sF7z65L6!nkDMr#%@flNp* z43A2adPpRk%R>9DV^ch=sL#_^Ge$m6zRP$d)en?X2XG{8JHh=3S# zP+1-Uw3O2Eb5*8cm^xuFr^xB9d8GEw@?r~oQKLi(6XX|05<^Brqc6uRj&=}L)7`_m z!oUva8KK`5-!O2aqWJapSUp_jgxuv2nl0*r#hgRSTj=J3(&I6V=iKCw1J2Zq80$l@N0ZeV~8;_@d3%YBv5I-GZe6y=bqOXzoHbOkdX z@qX`fke=CIh3Wv$xG#_lI@M z{MJSg_UlLg>0EJwS99Q~$H#T7YyFU`wM>vnjrAVSoW#UlKAL46*A2UbeEPmSIMO@N zS=p{_o0O@(4=m2=%G+S54BPK5ennF(&-FD!(x43OIkv3{4mrMQ52#`ZeY4`LsTk%e z2#dyy<4y&jJUnQ%giw$d^EPP+kipKA3IifGEuTSw^T2KZ$zjDc>EBl8J^Y;+Rt_R1 z`bHSIbMc8wpY`2r;I5x2R5*aangmO>Z`D-uL!D_~Q)Caka0PFr2MNe`S~)X5U?96j zZ6pHy@f5>L_X0XSz<~^ll;8IIZe7(xA5anz&EQ(l>c2qc|AU5UhnHKQ>2^lnO+!Ai zB_vLW9^9#*1b2|=-1~KdFAZ28K*n2hn1srgk0)WB{Oj!DBck?egy~ z&gK;rUY$QAaf2El@uKv!x7Fj?NZlaAnOLe8pu>-1#rXCw>w4&4Mo}e6k0~!&cb)}- zAQqLzS@(AEeA#~W$zfK*z4>D+5z5MY5#VeS1ijGt_%t=4#)F7u1eK`7)w(9niR+^{v^ zgCQKI*lf~+fGY7g^t~aFVSUMefUC4cA!})^sP7xur+edc2&usM=R#tTRMFMalxiV5 z*lV@<^unMqQXDtUS9Snood;2smd&t)6nAe*W7`NJmgmrjS$b~IF!h+Z(2SH)d8wrR zqR`2L3XQm!C8~{OabGMqNhieL#u9%U?{myI8%|2J>9p!*_0KWL*?nNbJOYS4WJ~^Y zfpA)LQZeKJ zmo&-mwH+zU5$UQa@2<*9>du4*)4H_y+5*lK9Mo2Z{C4Y*^Jm+=75T*B;GRXCk7?|y zQ(R#Ed2|B1IiG4J7grflUecrhC84*}`Kncfzf?6H-|i(2DP+&( zrA&whnVzX3zs}VV6tQaqhqu}E8>x7@vu{Hrt z7mu(Y2u_mIqtdG}+zMXn4eAvfcmOz*NpOF-o2Hvm8=@pKljxq=Yr26H~< zf}vJZRQ;t%$r@7D7f>V`ZkD<}2K{q0b2>;iEeYts8%p)>L~$l8M;J73;m}q_Nc#sy z<^z#9ucX53X)&mxG-;Qk2HmB(&e&3TnDJOczu@)(v$swLJN%%Ax-_4?b(KvpSrJ{l-d<)MH1H=>W zoVE)-U+pNq8_x9_8E_-T)SlB4K|tPMHDXIZPqnswPY+#L-Z~CtpRf?3O4*Du2rBj8 zPmG>Vfm-ub4SBWV5Y(&*?a$RuxV4T5NfLxab|J~lr3VnR4B#G!3^DrcWDP3j=&w0? z>PGOZ$I!3>-~to*-cTH<*#h7UEhwoXOZSfnv1&tonu6it5x#hzGJEgin$`r9;~`>! zd$$TH4i8$l4O_QOX}4;~z*YsV5pS76#nWv7QkDq}aV1sqq{)vPjV_*cQ;%tF6t2JQ znl&&fqwRPUaI8f`F$K;+QUO^Uz4u?iVp69^_NxIl5i5nn$_$hrd;Zfdk_oJ)NLrqI zpkB7#j(7-5<#!T;gTkx2a~BdINqVl4ZsF3tv$bg)j5rti?fD{r&y;;-k;OIMOrHPV9+qi-CeK+@94 z7hoM{G!)b$Z`Y`OtN80C?Dit_ka+~$F(#rS|NMuK$rzJ59pUudk}ksqW^4%xc^OgA zrfHps7=!>{`_}4G=|4qy;$H8w0$2dtl*kWigaf%PIkmYQ4Tq#rXQ&bKZzu>T5uB>% zK_#Ui@HR=&K(a9-EdV;7%J;*s*#(=Z1Dxw6!S|3&fM2SO4A9ly{zCQ(pTBMq>dmH$ zGml@b0(vMweaI0D;ipP54d_gY0w?rDom8ed%X;f;%dcE|CevsqaU+C-=<*8hi|XHm zi@&?f>4v}irxBv)wg`U#OUK3qT9F(Gt)I-kqL9lekOls{JmYX(inb zIoO+Jv&b|Il|ASRIV<3T zeXKi5Ps}?|NMV4jKba;l2aM|$M;+SVy3;yuElMZtBL+2y3Bm<5(4=$%fV+!S7*UJu zp+ep@Y~afQf`5cz;Q&n!&h{e;zqPyM@yG&Vr|p)f9%^ppe^Y32_Fe(f&h8!#agd%> zswCRMqVVrYV!bJNKs&_&T;npyhHdy?d%`5%L;3N!^bkOn62}21!l*U>gB;ZLx9P|d z#j$a{rcQs%9wj2kOGKEKWT{@HFU-Y;;3b<3| zeG2@#2_-s|B2>f?^V~tvb*6mpBkkvYo8*iUgT@vE6f~LZjo}a5A*6jNErslW3bkI;4f zbJ%M4fC9wZ&R*N;lLtULidr0}o=5LfrH(%70v~yf8jeivWd&9HqU@iCaY`&enYVM=s8D~6B-WQvcw1Skdv<8OdXj>M4F;O+Bmm^M~G8R24{-$VO0V@JE+3l(Gc zJmI<2z<(lLQ0S9D%l^Uv+-n5Y$Dw4Xco5}q?rXvEdf!jd(=Ceg~AOVwbR1)FTXwIy({hC3~9B9UXcbRga;6Tx&{;aUKT!0k^R26hY+Bx zq=XLo)k@p69WL%2ccIPh~Gc+U-5 zWl7Ax%x3Tft`qRj+v9Y-e}soPdvT;`aA|PqG}(Xo7rFdhm?(hp@p5*!k+M_g_4S}! zv;IxC;c?c#z_p=eZqFegz|F0A{qn_jLmybLwCXOMNro3*&goGyPvu+pvYAIqsj?g95G29(uH&8&>78Ey ziMNz_+0SDZ=CK42rqQq`MB|{qR1k!8&cfIE^A1jv^i7JzByAsQ2u-z%kmczSOpmC9$uky!YBCS! zWpU8|zI77Q{D4aX$0R1Z5mSr_Iw2eb21kRVYk#f~>g2#iJG^MgC)51Yk%l{;#u5H5 zZV2iNIC#;0^DnQ!OUB#pRg&IZ2@$cK8(bA-Jq{d=#|k%EcO#%~Y_Hqu8{Tm3TTO_#5=VoBM)@$y{n%)Knhiq|u2g3wb zWjKb}&4^_&s3kZP!}y?SLEsfTZ^>l`xxf@Gq&8E^qSZtgd99W^BGI2Kps_7x9HZ|2 zU0{R#>u^pX>4x|2zpn2yI-L)#{^?(FApjGYFEEJ2;cVrVp`<~8Upt*XDRwKdy9iiB zG0wj$Sx5uX!hMpi}Rb%rR6Poof%P+FuQBHz1TQ=R%XLm$1rS6+AzPb%i{XwwnNlzL;J5Ti@tc1>a`Zu@tV=9YEc{cacQ4v0R^H{)_g;uOL4Vm#Fp=+Q1dBGL3{#M}x@qhBW5 zaY(5{yKXunYp~`1RbN8?^sfl)2t&%3G!pxUHLZtaM)-T%U~Tiw%YXA?}To*D*s!m&?d08Asx&B&S!n7W49`e3eBWM578bU?M4T;h-Q0vx1K& zYvIZ8%=bS-Z^)>!KTa7r{C6-ANBFdK@KNqRcyGtK)^d{D&PgbMAzNAm%&pf_!E{=O zhX!=4)F|B5j>bgq$~pZ}kLh5Z}tKo>pzPI+a%LYqndt99F!0``3%3xELY-xm_zJhL3*b^WweGpKXlcyh+fa zPnYwyj=tgh@X~cR@nG;ctSF4evSF55;8fWq@RI^92mfT|6$G}3L{G8qZaiRwY`OpS z&JMKf7~xz&r`5J?0{+vh^_yD}c&}3*66&+9Q>D^Sm1N>l;W|(s>sF^E0N|kAtl&ng z<(QYd8egnWv|q&9ZAgeLC+TO;&d)^_4 z)_&w^a~xFUwgMx{QnVOx4$9rWA1=RC^@kNd#iEk=Kb065WvPjapVVT}xM^;@t}ncm z3cena+AN^5k@r4Fm&>JwXD`Eew5OF&a?rNI&-w2HZc?c;MDo8%(`v+idxR7DtDx2KD}2Z62>z5_v#OQMH(+j$qoDu zaGk#({L!e%Dr<99jC9a?y0?wPgAm_7A$(fo<-d#X{+E>ozZv@MrgNOsR&fuy8I7;5 zMC57PA1}WU&Hp|#Z4oxQihulpW8vfX;c?-2J2}n2RxMbmBgLIE%wlsND$7Kt&ZR@h zk*dwT+AV1k*(nMOspLDF8W={T&S^(N%s04Zb?zNiwpQV+;;)VJ2%)Q%Ixc*IqLi)_+SK2QbVxWSrQ0AUIHCx?PowJP!YnJ^}PR z);iv|!n_n2;kVAB+a^?flzAbFxdm5q+_zCZW=7j!mcoK0MgN2Y0@SIXiJAuiIAGXs zfRUg9Hx*KNduf*^#S_{Az&uOj57q6uUevC)P{HqA%NhD~xNTMwyVrNuFgNX(rnaq% znvh&TC~~Dd=YYGZuM6KtAbpn z@`d|~uU`Q`SE^1zy^c2uGc)^jkCy7{t7k=3Kt-atYk`l?SYX6Ve!T8VLd(_ni$Cu_ zE|hqAEE7-(B>Q~Jb!*hs`V){V_spNt%*q|;z7llOq|!RN(1y|WLi2K&Ry|x?|F8f;V$P=lC7uRc&_Y4RQ>d!BQ*>kSP#8D@dJ%~wM3%R&4`4|Y|p&W(O z9~i$SC9@Yv2X6KfYs%!xe0@wpCG>tEx)CGcTB!{wlw@t?19Am*<9kK6TXzyH*NM5I zEIbh=LMQrc;%R;M1J`xGmw83M`jeXWzsI#~6zkCY^-w_Jpsk6C-L@9BsGp`6nbi+n z*-lvL_&DijCLZgJ#&t~0M+#vOFKlOL`tE9*fO2vL+! z5EX5?)L18)p5GB3N>s6h*AaRH=h;czH}@Hd0!iuMa*L)hi4*0{*WKnM1(!cUIWJu^ zgTph$_s0xkS({1iu7p<%?hHTf7J`bVjtaZsjiT$ecTK&_2Lhowe5mFLQJ-}&C-k9a&(h>JA z9VpHrh+D*8WW`7a9PoVF5^LAtq)&2udZQbJJ>);1nfgvDGJ&khF?Mfu{F+qxs6tL0-=%J^XZ3NqJ7IKEOJDAi**(b9}XYtR|k{Hu>{q6ILtTV;O(5FzWXyhkJWXz z6Z${x_*Ic2NrUU0K;eN2!MmB)LoP@}M0SEVIM|TD)5XTU%t=4n%{kPiNYAU1ED{we zXM8x13bgqjdMIa_2z&WJ@T!|42~q_2(8r<|Cy6r41W)tD;bNW1+KE0bEvC{;0Njq# ze1cewW-$m-Y~c?fHiAOgRvZ1-UTuMoo`o*rqV9k&;Z12XC`7YCH68c2J<5fS>vvf+ zq?bdCkz#9k70mNaXyGkd3jAMU9_UDIpQlU!|Ck4Z!Zj6wnR69xT$eLYpp{7$6~8+- z0NL*ry|2*^dN=%?Pq8Oi46D|kQ9-C4G^2QtB-1OuFWxH^A39zMHBBLAUCP4A5|T|3 zZeC~Ez+BedXUj0#&hs67&0;Z}4qwI=L~Lfceb1CERXh0k-4}MN+e9J3Liyfyvz)TM zyj!D!J2)T+T#MrJqdfm}#1eIJY%DqvKF=NGzd|J*=c_NA{&nYQL-ArIz))(W8MY8^ zZo!Ayt3qWN1AGo;4s|OUS$kB-O%&N~cyT`FFq>^kp>N{H_{bTM%keO^j8|k zkfF*$c^|#l19{(3pis!;OCKA>+|QO8E@}na_a|1cR@flgg{X>>#gt`;i<1-K6ykKb zIGLM^{SECj(tM5=5Jq5h-MQda@4`bK9Ty$>q818-TvPEQrFM|@d4m1|Slq8|K3*~y zUr9kuf4{+Lrh78Qufd|8ew<9+uY03M^d}I14miZpiLSrm6Ul}vN^4I@`a#vfQ zXy%T(C6elBRJ1H~--H69kgPoeLuDR8SAyysXbEuK5z`o^zK6p^0#^}=3)fz>%bHU^ zTKq9P7W6$fyZo9D22RSC$iKuWAtfPDSChLfeU?g?m!rfriQ$~#TSM8=x*njXv=mVM z4aMVx)YLtCrr{vliQxpDs|RG|ne8Y>P#j*C{74QJU*{s|cdSG7oV2<~H9stbbtF7> zG{OS3v2Q!t^nbH`*b=2r1d(H+VD+fSVoOXcxbo-7!BI2HDcWwdl!w?Xt6S|LGbKiQ z6OKAd#tOXne~d5wE9_ya3WMHtiADQZIun-;fJfcyS~JE;pIpP%xocEM&8CYAKsccv2*Fwi&he@U&i(ec}whR z(_($kYzDjDyIwrbmR&wZQTc8+OM1i5^z_tURv=E4KL?3$%j4Y}!S}2W_tz5xP8)V? zTw)m;b0VeiK?M>z{(2}a_W%86yD9cPS1uJm^e z?7E{<-4a#Jg|&7h`6sgwsK0qB&@ZMF6}jo&dWsMKM69-VuOgEETgWrowq89$bzM(Q z_?+vz+|AXQCIX}o5;49ebCK@C%K&kiFhZF*xqMG)4Zh#|3#7I(1qHy}`9#-$$)Zr_ z7>(!PbKKbKdR4VvnJX|AlM!d7s3I3*N*a!ykaHRMr2uO(r=%(sQ{zvTQjaN9xt&g<@4rB~Qz ze8`QxR~mj7XTla3F0!%UZi5%PU5 z{102K8{(qdRO4-mbW#zHf+E60DF#O8tR+e8H@y11UkN65Kexi1Jt|zx`b{FvCqe0s zTWClRGVrtgPX(^Wn&sKdaxmG@djo^@JJ_-QH~7P@8k4ExCl6<9j)wjp=XxDF%|*}8 z+egW0aXL4)Ay#-znff#uh)>t6zJ9*O_Li2YIhu7HR<*Y0lWFEG?bk*Jy82G2Xd3$lkgR!D(z)7W$Hj%Vf;AhBZie;p9o@$--X;npKUB}oKqW``qp2B}5;)Tu_$eZ2Ak2|H zL{?Vy&>n&~AG86x;fVM*SgX>yUgcIg#i>-G6mHNTov7Q zhx5!2Y#PFR$IcT}zmLCp-^1P9@Itq`Ni?@@rD=w~B;BTtS-HBGd}E;8v0jS<^JH$t zE0?QTIN#{Ja7vm|%Ek^(^L=IUrub!(;!uGDh;O_l&EQh1){_v>1P@&{?PIDfz3p?J zzfAcMr%b!8(PQSqiAtn4{4~0zC#EhY9=l0Of)0*m9>DWmOy(-i8Xg-Hx@c>`(~*H8 zv5P2ye-41l3ngre3|EdmQzTPRx50J7eGG4#{TsoWtZDn8v+?JJ{~~#~sKADWDHV|k zgdB)uRVYPWME0}Q*N-A?FPd57eK}l0k3PV;i6w2)R{wW*+Dy$l&)~MMG!+kZ=nMMQ zfz9%3@l~MwF>VpXw$J)~81Kj984DqL=DM-!*0*UMbQFCtHXc@$nOjwsbI70Xh38tQ zZ)s$dtTS)?-{(#Kq%M6jbzt@g{vQz1hL~NbFwj`kORiHq1->Ap2S@7pkJo`-8@70f?(DYaw z$nBh_r01Td_Cx-_39P2!G5H5(8-E?##|4Vv%Da#}JeJ%+O`f zp&3x?4+0~BCOuM=6->>a+ZJfD8Q*bq6X{2*DZY2XejYmz7Xm}@0Pp*ZOI^R$`3B$V z;bTuwP9Jq#czKRqyv0UPxsi&{`1aEpa97@Ww+_pYQH+v$@ z=_eOwE)j#)f7rUc;ch?msru3U9*WY(U*R1Y?bQk=@RNbvP$;6NhX3OG!obEeGP)4X zK#vKop@{dWF?|R{tRl4rO+#xHrKpj@h%qVJW1>iS#Mo_S&AM5qoDucNK}*>pD~a9J ztY%VpyV_o(QS%UNRF%cI`cjL@myL#Zw=Q$3L}gUFh>$xCMtz#>AXt#RSwl)@s$8G1 zUms1zO7LSB35j{slP>kfLWeoGj+3mCKpdTkSbr`M7`^#SwrMZUZO3uY`+Wm*e^`(D z-%9%n)Wwy+KeswR33{>r2{$0*Dg3ZzIJUEspUBf-L$r1(gjzhQ?oUx{B~h)n7Mlj0xh#1~ z`@TakF&d9B5OjdJB+|OLvUEnUt_Byz57n`^$O>$MY3hqrOaipy@QNl!d|NQ|h=E{< zFMkhQBl2~)czZZ5p{8Tgb|J#1$Lz*Ckz=qy0BK-qcy9|sYjNSG;+8OHWSlFwF|6E9 z7gOiW1l3VC9?JwRlR}^YcyR@3#pC0`jmzY!H-6oSUYv9uFsw0U#hUdcn&UNG5+zn0 z4cH27Sk`*6Xe#>Rx#@zO81ks^QreYsDw`&R&j9T?d1*GG1%i~CHR%?tBQ(dpdOo9Jh05oimf}8}nwK}bKps>$$b%@ zm-ve56we~B!Wx}fBR@7FO&kCRQMDS(I=D*zI|PNEWMcn-^RD_r!GnPxUzRIuHmjMA z<=%GR1`xgtSO6oTnf9Ew_XxS`ci0WWZp=8n-MJUeh4hoVZuS1Mq~nxRnTfHkRL*eZ zskin6vY_~Fk(#2WMOIf4XOm)iJpw~mFytO&8n1_am-!3qMh=&&R4u1`kHS^dX-^VV zFmsT3A36~)j{Hl@ixI|#;Gn#>g&5lY*Es%T^6U^Mx#}4Tc;^sC*J1f zA0@I7@gw1rv-E)k8Nexk0D`KGtr?N#ZUH> zlONdmI_yb;TM!zL-v)^J{cn=+)`9 z7g_0NtIjHc6F;p%%QmI*Ihhoh0$rNq(PEhZn0>hqSK)v=L&&obch&A}q%V5;Y<`0< zobyC9*_DxKDk)-e@_ln+d{`QD<*k40Gu?-JaEui#4%WY})U0&)7@lR0CZ6m2anX@d zk1LmRu&dz_FbI5zoc9e+XRyxIIq|1a&ID7`6fM!!GqFOH1U|mM>8!sEUVU8&IWnyt zKUsCd2oH`gVPe-~)UfGy=GLIWk|{PWR-R*V=|jMn=3=`%Gb*A z7Z0}`1|nF8E|4v!kn!rWX@satbjdsA7aQr%J}XJ2-Qf670BSTL%G?@syOEy&bgQjG znWPih8&`P=Cb(nhrGicr@p^y+%kkCXz|hX>IcDpsZKT@P;|ksye%}aRI&=a7^vse; zixE=NeiaMnK}8IOY`Pp?gRET4IRrYcC|d}YWPJNg|67h$ClygvU1j0sQlRo-sMcJg za&aOpRzrwL^S7!Q!_0ZJRQFt5FSM7*3kd*dB3KfQ&w9&=hgeG7I?iF^RYwJ<{bb;z zR=dmZu6v7v1T96z&b*nAFI(_QfYY~Hu?7R zT`~-1&S;rxb*eO%kRD%wJbDboJ!iGbj1n-3>CjoTS6P-&9~>$gj@2ahR~q=51pE3X ztXUFc8v>`dwod$qvok3&bxs05^&+;&{^LH=qf^84$Klnwosby|8j~Ff0Y&pgw{xk} z`ISR@hs2Y4X(Mg;5ObV8Yjy(~v+JiPUxB1a?2$cddDakV=tF08`kX$$Cb;ZAcQ!oC zFmFi351PCgCu`$%PZF{|_$9oZD&Ca!dcVzzJE*J0;t4JPf8ATGR+-)$I=EkHvw3oO z{aE~8#he_=c(~0zJy_s@Td^yBS??~@4V9`42a)})y7mldqq{dx%B>Z1a>N0D;fY&c zTDtn5QYq5$=TbmEh%&_Mx3l_IJ5rI7^iBaa0jGME&yQ%T@>SN#2a70~s#*=TS zaWl<-G&+S0 zsvUK4DrC5Yg0e6_iBg(D$uui1zxit81K3ecT^*H!)k6L$&MgwEQ zqyjH)F!4&01nWYIjOP=bTudeNT-(`G)TVmS8NJq71wk%HF7oMF>yBgi~uZ5EUffQT=Y!bs?4lBOe{Ri%(P5Q zJWNcrGqDo?PX;>&Q!8_?|9^({SdRak05!Z-HC>gBJiw054(3+2W?)w@M>DXMqpJx3 z;F-O1jRfbUPDM4MI65Z1rwo81MPx8RL?=a;O~Qae2a5%;^_oJFHmHI}7iWk1#`*~Q gU`GR_@?{tR$Jij(YZ3O8PZ0oVaRsp&5yPPW1G~q&h5!Hn literal 0 HcmV?d00001 diff --git a/src/main/resources/static/apple-touch-icon-57x57.png b/src/main/resources/static/apple-touch-icon-57x57.png new file mode 100644 index 0000000000000000000000000000000000000000..b2d881d0cf37ac233052a718af22c22cbda52661 GIT binary patch literal 3667 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 afi$qf#fIF{R>-=L0Q7Z?;UBaeWBvyxre3W8 literal 0 HcmV?d00001 diff --git a/src/main/resources/static/apple-touch-icon-72x72.png b/src/main/resources/static/apple-touch-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..dd4dd5c365e9e5e254a37fabca2f64b622b4084a GIT binary patch literal 4783 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 D>4@yx literal 0 HcmV?d00001 diff --git a/src/main/resources/static/apple-touch-icon-76x76.png b/src/main/resources/static/apple-touch-icon-76x76.png new file mode 100644 index 0000000000000000000000000000000000000000..6c08945932a94adcff2e0b5962ee449ba6df51c3 GIT binary patch literal 5107 zcmZ`-RaDduu>KL!AV^CsAl zv4mXy_w7F1GiT;I6W^SfmwA|2JsnkYl7}P!0FbMz!3^$D>pvyJy|ZekL&0}|@1UTq z000f|Nv~hryYoRdY6jW>5XcPx;Ya|uybFc@0stRT0N6zUfK(;`(7Wfh>&x6F2&^?# zVZiNwQrK0Iau*@=R@YW0+#w<+$0gBQ$YTY72dU~X1-Sq6K~6v-v!BoK`qfS7s;q2N zhS9>0`G#acwnm|Gu$=W$y7ef-Ar2jdgv3yJp;}ax9z03IAl6X5uznngPohS(l2qvcL*x8K>%`WF(q ze!hn3LU)az4p+Kkp9BFrpecp?NEt$`dD{)Qq5(tl0_jEM?gTe3fZ!l`{nA=SCh(Kz zFNB@D`)Cjb)A^_U_B@eBSt27|MTI{SZ(fP8S~cN~4UbDv?*bTsVeu3G-Vhp+s0G_f z&d-cVV5z2Ht|6m%qogDyJ2=k|fhZlk&!VD}AeHX;-!8KyJYV{wtMQ`0l&BU@>zfPK zHK7QZ+aYGGgmV$NO=f@>5QxFpN+o+;0GKC1BEfSuNh+MNS zd!2BE|D%gKwhF78XMyY8*F_QEH)A!5KEx&q80Gg7P2nfUelU=rrk+03d-{};m359s zMT>i4e)q2&>Z{a6o8&7Uolxxb@Jtpn6FESJzXP(HNB7A+J+SfD%OgNx+`P7?aX%-fL5L!p3_rl4Y2-J^G(HI5S~EZtKvBgNi==zD0t5l znVmKDHW>yNE--?A(CmZFB7r7r6m!I(-;x@vbZ?`N%ETJ*WZvT% zIsfPxPE<`xreVSt*-ZA;Hd9m+C5e)*gH0N;Jafq=nzHsDYzzHd%esVQ`)I~;S{Iux z1hKT-<<1)YIy>dPzr01_%pqy#{x)n4NR=JtD%TrE zI*7GT{=~DlX0Jj&x9Se)I89M|l*tfI#fT3;B%*ZL{jtXpcH@welqVwQ`y7)-ZUj73 z<^%?U(LI7Z9wzg(2-z_D_3OdH5R!Zx zA9(yG!gS1EGB#Qm31z2@V0=D7CwO$m)fKwY;kETEeF>LT1qXqXO2bkKYcpwafa`q5 zA*LK=w6}Mv3?r}U(F4^(Z4tdDPzLE(k)Ajn9Z{;hb%(mnmDGCyHJpf@rikYAn zI!ZX9-{L5QPH?C4thxe3NgIiF&mr#0Lg55LHTvc@l6M88AopnK;8k zYkOOj#dwi_U%K~%mpikvs0QOa|211fwN~gwGzN3$hzzy2Ne~fKlsJ?)St+#;@M9Xs z4at*t85M3^pPs%=toKYyR4jby9HY3ud~f(YgoE<|2i}*(R{x*G4Nk^3pBW9GFr z&6nzrNn;gxqnyx6@&{s+js zMBsfq>A>Pmxqirc+o@5&skra0+{uh<&@ale*&1>XxNv0aiBp~?_x3x-z$+IbwrMXQ@Zh#rP93R+t-zqjzSHcx|Cj+uX``K(qEbKKz{ll z0m#|e+m9=A7z^E$lv zZz>T0`*(+}oU!BxcL*Bt3q7)R>I%0<^md2#28_=;Yi&$CjjT4UGgw6PTwdlfwPY&c z%~#~Veg19GjEB-~_s=o#TqNz@XG#*_UMBiXPp|Fkd2qztS#`05+5+|>S)Cg#E3T_8 z2Wb)gygSp@t`5YNJKh5*ErrUW_Rp0q& zGM>AO!*Dr#tnXC;jkX7`sCOwd!H{CtJ6cs1n^EoZwbP^bJvXxFFFy`9nyQZ7i^6wR z-=i!>KNq+;LAU88&gLp2NF5I%OfN${cP2M)&KpWH)o?A6j-Qk#Q*cbuM)Rk?5s-RB z5bn<|mi{2m5`#^V57|>|Pbe?9Iw8sSC^0 zzvHS?A#5YF3K!9hO8x~ z#Kguh0PQNOkzv=-Zo$9K3xYRiqYJ`{vPFn0OAW+D@_bDrQ13+AS{pq!pbfUM*6&Py zKc&BN#q}U40-#WiUCZ`O&VtKzSR=fgpQ)IWGj_>&p=t zOHF}1?Y`fJYO=bmFz&`4(C#g`EP9;SVLD43wB^wT3N^zPzNuz`gIn@fYv=kg&H3*D zRHv4DmiwEkH<`+Y%+^jBHD;$tx}nzN(rZQ{8&D=l(m1wuqa(kXMi+fTio3KJ_q+X7 z&Pq?<&m)nAj`y9yY4C87QZJtKgVFt!Cl{NB=$pQ1k+pz|#HxH{goTvf>1l*PWEwxD z&L?m2USL#Wtqj#tD=i3z@+Efn876ptde3#K59ZU;XQ5Yxd{Ke9%I`RgsGxI;$ujYG zJ(qUXvSF|sD3w-CvGM!7vzMXKN ziV^2KZeTbCV#$48lsZWwFT*PIG^4xzdPvCGA^+r2aiwCPq0Y?RiJonKT<4+ zjYiW#L?0^m7Y1`%-Lv1iTXn?KZ7La@`RT=WZE9G5*LiKH4VjSMnU_(Oaj+~ zIzGDyUH=?BF2W&Dvuvw$8b9^O;-Ji=%2J3q>O-r9HLFIr+mjXNCeicMIRkHLV>>Xl+5`X-liyNX3zM1C zdGOV`z;8Y_+nOTtj*2q#7K?w_DQ}CwQRgp<3M5;{-$zE0^Od`I#O=IJL>DFO@8x9U z4e*xfIoe}!!nHiKkpqk0b{-h;o?aTtFP^il`zZKpx9s8yt+)GZtcUqZuv00UWmLb= ztLzTFUK}U9uf`sXrj6e|4$f_4;mVQ1>+L&q4}IC{q+CGrx`wMN599WS+Fi*3u$Mc$ zVf%NHQqVYP{Q%alXIa?IB3*m&t-_GL#)T5x#04Hw8G2d5X~XgHoQy(e3xc%{Jx%61 zX`E?cr^*?l1ZWK9ucy$yUHfb9{dRt9-Hs>QFkN~8Y}!cPl)upPRIK5ONmu5)OvJdt zjBNhi^V74>me{4?KrHDgJ9*4R!$u1pb4f>wgdFRPNxtlT$FO~bQu z59>d@w7uvx?!Fuk!=k$dYE61h%jeM+A#0aDqifH%0#Ky_^BUcWOpKEMeu|vSpGHy# zg$@pJn^`1XVLEM2*5!8V_Bm|?lNyYisGGn4R%5a`=-W^l^b9a{)2)SP^4m^fEXOK3 z1rKg*YlV~{qP*-9-sSahx#N=^irZ^R^l8ewAnA0$qmGW4Rx@6BPEDdL%S` z!Tru5k3%-xKLXPa{cG#`ci>Yz9tY?(6p-wKhe!MO$@*DgM|kS}^eIz0N}9!zB$iQq zmGLavy73MWSr&D!GR|kUsZ(hr?>gu_R+No862De$KIZ8UoVvHYkwlPr1=Hee^T2t4 zi(U_!vJ1PZ*C~5#?LpCLGIM#goY_as^GQtOu8F~nSrAyZ`$GxSP5`c3ehB)NnmsPD zd&Hh-f8s*Z4jm3WQg6)Xd^Kpg;KoDzhq73anAu*tH{@sh!Vvz}*x>*&*+9LrG*J;` z-JU3v`c9T*^}rZ)z&ENl<-h&(N{C@Wk|Z-aF3ZEjbjtaGL2b}_$lkwSHnhXBZ~MNn zniz|xPcuNkl8o>%&7gJ`J{GQxMkS^Yudv$ z$R^hhiF%H!R~W0CXtqisD%y7y$+fQS;wAB)7_&2>Kp9NXo-8)T5bLcc*@HeX{W=LK zbR|3EILnQTWTJ_1Q2nr@hP=$L9t(08(Di6}6M~r6h?b2BTDLd}2`hd(lBhokrOEtf z>NP|e{{H(tJHJ~j$)AVB^ly` zJm{y!Vju*;(;r-yY=L2zAPjL_EWf@N%DMRM*nB;lk6xopv63crY|Bv`oE@uQSORZ@ zOTOYI;x}AUbTf7^9@E9fB6l9zSV?++@3C6$D#u)t?=1))9E5DB;N<&G@Ucjz2l?o} zxOKvIUA>OzJC03h*FzLb)@|VfxRZ|_j7GCsT>t4Hb1#jrjQH)ykXAjfSebkO?UG^x zCB8!0gWZ@IO0hFpRX){0?y8?@O6q)N-ld+*TT(h-e6Eo@QaTKbd@x;yoh|z3?h|$y zzGVgu6ibV0d%P(^_wUnFbmp&j$bWXQa=%csbN-g9p)LOu>CCRM3k zgCKL>(i5z6k)Gh)?Xn#mf+rYg@TqE)rOx8g^`vSHVg|0}{1OfLe)G;BE>?@I)*pR2 zB?TmHn&usStQ)=mnz*k2`XPI#u7_GQv<+qE^cN-q;-3&ARO)4=<`ng~$Z zS@KrM{atq7vx#4?3^P-z>O*6gARJ{Htvb36#_P!^Mj}?}hn-Q;&TE-VsT%Xs)87W> zaJG#p$jK<~zpsFlX$+cGmskEw>v}WyS}M{d+d|Uu;i8Y_x|eivs4;kcb!mEadiuxJ zuD9%BR7CCsvx>ePulAPb#_zxWQjoN9+Si2^eLcuRrNCX$)yLuN*(d>#A+z@ZP+pMrsRlMV$asfEp7sQAA^3}dH1mbxV)83 zylr22+ez7Y+T8&F76n6uM4t+YO2Wk;QlelfF;M|gQ7KVT;?k(&|3h$bvwdYB@c$G1 zv9daM1mi%siMPQEKajhpoBb8ZSr6~)v3+d^Gg K2Ue?yc>O^^KklDzeXCbj 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/static/browserconfig.xml b/src/main/resources/static/browserconfig.xml new file mode 100644 index 000000000..a47e5a5b8 --- /dev/null +++ b/src/main/resources/static/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #2d89ef + + + diff --git a/src/main/resources/static/favicon-16x16.png b/src/main/resources/static/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..982741bc12308255f31b414c54a4f429762f10c4 GIT binary patch literal 1473 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 CxVCEm literal 0 HcmV?d00001 diff --git a/src/main/resources/static/favicon.ico b/src/main/resources/static/favicon.ico index 64fc4d074ec9b85a88047001f430d15e0d689087..90b100a490bebe06ee47501a1e7f107b8108a56d 100644 GIT binary patch literal 15086 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 z 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 pG&1A<6K@=)zM1ppwL4giq5Wj1Mv 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 Y`{aaPe`N$y5JLczU;qFB literal 0 HcmV?d00001 diff --git a/src/main/resources/static/safari-pinned-tab.svg b/src/main/resources/static/safari-pinned-tab.svg new file mode 100644 index 000000000..f5a17f970 --- /dev/null +++ b/src/main/resources/static/safari-pinned-tab.svg @@ -0,0 +1,41 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + + diff --git a/src/main/resources/static/site.webmanifest b/src/main/resources/static/site.webmanifest new file mode 100644 index 000000000..42f8bb0c3 --- /dev/null +++ b/src/main/resources/static/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Stirling PDF", + "short_name": "Stirling PDF", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index 424771130..74536458a 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -5,6 +5,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/templates/other/show-javascript.html b/src/main/resources/templates/other/show-javascript.html index 4ef2d7005..ef9e014e8 100644 --- a/src/main/resources/templates/other/show-javascript.html +++ b/src/main/resources/templates/other/show-javascript.html @@ -54,11 +54,22 @@ body: formData }).then(response => response.text()) .then(data => { - // Escape < and > characters + // Escape < and > characters let escapedData = data.replace(//g, '>'); - // Wrap the JavaScript content in a pre and code tag and add it to the div - document.querySelector('#script-content').innerHTML = '

    ' + escapedData + '
    '; + // Create the elements manually + let preElement = document.createElement('pre'); + let codeElement = document.createElement('code'); + codeElement.classList.add('language-javascript'); + codeElement.textContent = escapedData; // Use textContent instead of innerHTML + preElement.appendChild(codeElement); + + let scriptContent = document.querySelector('#script-content'); + // Clear existing content, if any + while (scriptContent.firstChild) { + scriptContent.removeChild(scriptContent.firstChild); + } + scriptContent.appendChild(preElement); // Highlight the code using Prism.js Prism.highlightAll(); diff --git a/src/main/resources/templates/security/get-info-on-pdf.html b/src/main/resources/templates/security/get-info-on-pdf.html index 06cc10522..cf15ec4e5 100644 --- a/src/main/resources/templates/security/get-info-on-pdf.html +++ b/src/main/resources/templates/security/get-info-on-pdf.html @@ -35,110 +35,120 @@ From 83ba1899b7c42fc6f4e0c182d300d6eab31b9012 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Wed, 9 Aug 2023 20:30:19 +0100 Subject: [PATCH 027/301] metric filters --- src/main/java/stirling/software/SPDF/config/MetricsFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java index 5b8ffd67e..326ba09db 100644 --- a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java +++ b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java @@ -30,7 +30,7 @@ public class MetricsFilter extends OncePerRequestFilter { //System.out.println("uri="+uri + ", method=" + request.getMethod() ); // Ignore static resources - if (!(uri.startsWith("/js") || uri.startsWith("api-docs") || uri.startsWith("/images") || uri.endsWith(".png") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) { + if (!(uri.startsWith("/js") || uri.startsWith("api-docs") || uri.endsWith("robots.txt") || uri.startsWith("/images") || uri.endsWith(".png") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) { Counter counter = Counter.builder("http.requests") .tag("uri", uri) .tag("method", request.getMethod()) From c562d197e7805594f6512224297bbbfaa2c9a8fa Mon Sep 17 00:00:00 2001 From: Jacob Braun Date: Thu, 10 Aug 2023 08:56:27 -0700 Subject: [PATCH 028/301] Create en_US translation properties Copied from en_GB. Fixed variables noFavourites and home.pdfOrganiser.title to use its US corrected spelling. --- src/main/resources/messages_en_US.properties | 728 +++++++++++++++++++ 1 file changed, 728 insertions(+) create mode 100644 src/main/resources/messages_en_US.properties diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties new file mode 100644 index 000000000..8f9ac8487 --- /dev/null +++ b/src/main/resources/messages_en_US.properties @@ -0,0 +1,728 @@ +########### +# Generic # +########### +# the direction that the language is written (ltr = left to right, rtl = right to left) +language.direction=ltr + +pdfPrompt=Select PDF(s) +multiPdfPrompt=Select PDFs (2+) +multiPdfDropPrompt=Select (or drag & drop) all PDFs you require +imgPrompt=Select Image(s) +genericSubmit=Submit +processTimeWarning=Warning: This process can take up to a minute depending on file-size +pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) : +goToPage=Go +true=True +false=False +unknown=Unknown +save=Save +close=Close +filesSelected=files selected +noFavourites=No favorites added +bored=Bored Waiting? +alphabet=Alphabet +downloadPdf=Download PDF +text=Text +font=Font +selectFillter=-- Select -- +pageNum=Page Number +sizes.small=Small +sizes.medium=Medium +sizes.large=Large +sizes.x-large=X-Large +error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect + + +############# +# NAVBAR # +############# +navbar.convert=Convert +navbar.security=Security +navbar.other=Other +navbar.darkmode=Dark Mode +navbar.pageOps=Page Operations +navbar.settings=Settings + +############# +# SETTINGS # +############# +settings.title=Settings +settings.update=Update available +settings.appVersion=App Version: +settings.downloadOption.title=Choose download option (For single file non zip downloads): +settings.downloadOption.1=Open in same window +settings.downloadOption.2=Open in new window +settings.downloadOption.3=Download file +settings.zipThreshold=Zip files when the number of downloaded files exceeds + +############# +# HOME-PAGE # +############# +home.desc=Your locally hosted one-stop-shop for all your PDF needs. + + +home.multiTool.title=PDF Multi Tool +home.multiTool.desc=Merge, Rotate, Rearrange, and Remove pages +multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side,interactive,intractable,move + +home.merge.title=Merge +home.merge.desc=Easily merge multiple PDFs into one. +merge.tags=merge,Page operations,Back end,server side + +home.split.title=Split +home.split.desc=Split PDFs into multiple documents +split.tags=Page operations,divide,Multi Page,cut,server side + +home.rotate.title=Rotate +home.rotate.desc=Easily rotate your PDFs. +rotate.tags=server side + + +home.imageToPdf.title=Image to PDF +home.imageToPdf.desc=Convert a image (PNG, JPEG, GIF) to PDF. +imageToPdf.tags=conversion,img,jpg,picture,photo + +home.pdfToImage.title=PDF to Image +home.pdfToImage.desc=Convert a PDF to a image. (PNG, JPEG, GIF) +pdfToImage.tags=conversion,img,jpg,picture,photo + +home.pdfOrganiser.title=Organize +home.pdfOrganiser.desc=Remove/Rearrange pages in any order +pdfOrganiser.tags=duplex,even,odd,sort,move + + +home.addImage.title=Add image +home.addImage.desc=Adds a image onto a set location on the PDF +addImage.tags=img,jpg,picture,photo + +home.watermark.title=Add Watermark +home.watermark.desc=Add a custom watermark to your PDF document. +watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo + +home.permissions.title=Change Permissions +home.permissions.desc=Change the permissions of your PDF document +permissions.tags=read,write,edit,print + + +home.removePages.title=Remove +home.removePages.desc=Delete unwanted pages from your PDF document. +removePages.tags=Remove pages,delete pages + +home.addPassword.title=Add Password +home.addPassword.desc=Encrypt your PDF document with a password. +addPassword.tags=secure,security + +home.removePassword.title=Remove Password +home.removePassword.desc=Remove password protection from your PDF document. +removePassword.tags=secure,Decrypt,security,unpassword,delete password + +home.compressPdfs.title=Compress +home.compressPdfs.desc=Compress PDFs to reduce their file size. +compressPdfs.tags=squish,small,tiny + + +home.changeMetadata.title=Change Metadata +home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document +changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats + +home.fileToPDF.title=Convert file to PDF +home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more) +fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint + +home.ocr.title=OCR / Cleanup scans +home.ocr.desc=Cleanup scans and detects text from images within a PDF and re-adds it as text. +ocr.tags=recognition,text,image,scan,read,identify,detection,editable + + +home.extractImages.title=Extract Images +home.extractImages.desc=Extracts all images from a PDF and saves them to zip +extractImages.tags=picture,photo,save,archive,zip,capture,grab + +home.pdfToPDFA.title=PDF to PDF/A +home.pdfToPDFA.desc=Convert PDF to PDF/A for long-term storage +pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation + +home.PDFToWord.title=PDF to Word +home.PDFToWord.desc=Convert PDF to Word formats (DOC, DOCX and ODT) +PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile + +home.PDFToPresentation.title=PDF to Presentation +home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP) +PDFToPresentation.tags=slides,show,office,microsoft + +home.PDFToText.title=PDF to RTF (Text) +home.PDFToText.desc=Convert PDF to Text or RTF format +PDFToText.tags=richformat,richtextformat,rich text format + +home.PDFToHTML.title=PDF to HTML +home.PDFToHTML.desc=Convert PDF to HTML format +PDFToHTML.tags=web content,browser friendly + + +home.PDFToXML.title=PDF to XML +home.PDFToXML.desc=Convert PDF to XML format +PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert + +home.ScannerImageSplit.title=Detect/Split Scanned photos +home.ScannerImageSplit.desc=Splits multiple photos from within a photo/PDF +ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize + +home.sign.title=Sign +home.sign.desc=Adds signature to PDF by drawing, text or image +sign.tags=authorize,initials,drawn-signature,text-sign,image-signature + +home.flatten.title=Flatten +home.flatten.desc=Remove all interactive elements and forms from a PDF +flatten.tags=static,deactivate,non-interactive,streamline + +home.repair.title=Repair +home.repair.desc=Tries to repair a corrupt/broken PDF +repair.tags=fix,restore,correction,recover + +home.removeBlanks.title=Remove Blank pages +home.removeBlanks.desc=Detects and removes blank pages from a document +removeBlanks.tags=cleanup,streamline,non-content,organize + +home.compare.title=Compare +home.compare.desc=Compares and shows the differences between 2 PDF Documents +compare.tags=differentiate,contrast,changes,analysis + +home.certSign.title=Sign with Certificate +home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12) +certSign.tags=authenticate,PEM,P12,official,encrypt + +home.pageLayout.title=Multi-Page Layout +home.pageLayout.desc=Merge multiple pages of a PDF document into a single page +pageLayout.tags=merge,composite,single-view,organize + +home.scalePages.title=Adjust page size/scale +home.scalePages.desc=Change the size/scale of a page and/or its contents. +scalePages.tags=resize,modify,dimension,adapt + +home.pipeline.title=Pipeline (Advanced) +home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts +pipeline.tags=automate,sequence,scripted,batch-process + +home.add-page-numbers.title=Add Page Numbers +home.add-page-numbers.desc=Add Page numbers throughout a document in a set location +add-page-numbers.tags=paginate,label,organize,index + +home.auto-rename.title=Auto Rename PDF File +home.auto-rename.desc=Auto renames a PDF file based on its detected header +auto-rename.tags=auto-detect,header-based,organize,relabel + +home.adjust-contrast.title=Adjust Colors/Contrast +home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF +adjust-contrast.tags=color-correction,tune,modify,enhance + +home.crop.title=Crop PDF +home.crop.desc=Crop a PDF to reduce its size (maintains text!) +crop.tags=trim,shrink,edit,shape + +home.autoSplitPDF.title=Auto Split Pages +home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code +autoSplitPDF.tags=QR-based,separate,scan-segment,organize + +home.sanitizePdf.title=Sanitize +home.sanitizePdf.desc=Remove scripts and other elements from PDF files +sanitizePdf.tags=clean,secure,safe,remove-threats + +home.URLToPDF.title=URL/Website To PDF +home.URLToPDF.desc=Converts any http(s)URL to PDF +URLToPDF.tags=web-capture,save-page,web-to-doc,archive + +home.HTMLToPDF.title=HTML to PDF +home.HTMLToPDF.desc=Converts any HTML file or zip to PDF +HTMLToPDF.tags=markup,web-content,transformation,convert + + +home.MarkdownToPDF.title=Markdown to PDF +home.MarkdownToPDF.desc=Converts any Markdown file to PDF +MarkdownToPDF.tags=markup,web-content,transformation,convert + + +home.getPdfInfo.title=Get ALL Info on PDF +home.getPdfInfo.desc=Grabs any and all information possible on PDFs +getPdfInfo.tags=infomation,data,stats,statistics + + +home.extractPage.title=Extract page(s) +home.extractPage.desc=Extracts select pages from PDF +extractPage.tags=extract + + +home.PdfToSinglePage.title=PDF to Single Large Page +home.PdfToSinglePage.desc=Merges all PDF pages into one large single page +PdfToSinglePage.tags=single page + + +home.showJS.title=Show Javascript +home.showJS.desc=Searches and displays any JS injected into a PDF +showJS.tags=JS + +########################### +# # +# WEB PAGES # +# # +########################### +#showJS +showJS.title=Show Javascript +showJS.header=Show Javascript +showJS.downloadJS=Download Javascript +showJS.submit=Show + + +#pdfToSinglePage +pdfToSinglePage.title=PDF To Single Page +pdfToSinglePage.header=PDF To Single Page +pdfToSinglePage.submit=Convert To Single Page + + +#pageExtracter +pageExtracter.title=Extract Pages +pageExtracter.header=Extract Pages +pageExtracter.submit=Extract + + +#getPdfInfo +getPdfInfo.title=Get Info on PDF +getPdfInfo.header=Get Info on PDF +getPdfInfo.submit=Get Info +getPdfInfo.downloadJson=Download JSON + + +#markdown-to-pdf +MarkdownToPDF.title=Markdown To PDF +MarkdownToPDF.header=Markdown To PDF +MarkdownToPDF.submit=Convert +MarkdownToPDF.help=Work in progress +MarkdownToPDF.credit=Uses WeasyPrint + + + +#url-to-pdf +URLToPDF.title=URL To PDF +URLToPDF.header=URL To PDF +URLToPDF.submit=Convert +URLToPDF.credit=Uses WeasyPrint + + +#html-to-pdf +HTMLToPDF.title=HTML To PDF +HTMLToPDF.header=HTML To PDF +HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required +HTMLToPDF.submit=Convert +HTMLToPDF.credit=Uses WeasyPrint + + +#sanitizePDF +sanitizePDF.title=Sanitize PDF +sanitizePDF.header=Sanitize a PDF file +sanitizePDF.selectText.1=Remove JavaScript actions +sanitizePDF.selectText.2=Remove embedded files +sanitizePDF.selectText.3=Remove metadata +sanitizePDF.selectText.4=Remove links +sanitizePDF.selectText.5=Remove fonts +sanitizePDF.submit=Sanitize PDF + + +#addPageNumbers +addPageNumbers.title=Add Page Numbers +addPageNumbers.header=Add Page Numbers +addPageNumbers.selectText.1=Select PDF file: +addPageNumbers.selectText.2=Margin Size +addPageNumbers.selectText.3=Position +addPageNumbers.selectText.4=Starting Number +addPageNumbers.selectText.5=Pages to Number +addPageNumbers.selectText.6=Custom Text +addPageNumbers.submit=Add Page Numbers + + +#auto-rename +auto-rename.title=Auto Rename +auto-rename.header=Auto Rename PDF +auto-rename.submit=Auto Rename + + +#adjustContrast +adjustContrast.title=Adjust Contrast +adjustContrast.header=Adjust Contrast +adjustContrast.contrast=Contrast: +adjustContrast.brightness=Brightness: +adjustContrast.saturation=Saturation: +adjustContrast.download=Download + + +#crop +crop.title=Crop +crop.header=Crop Image +crop.submit=Submit + + +#autoSplitPDF +autoSplitPDF.title=Auto Split PDF +autoSplitPDF.header=Auto Split PDF +autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed. +autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine). +autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them. +autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest. +autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document. +autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers: +autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning) +autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf' +autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf' +autoSplitPDF.submit=Submit + + +#pipeline +pipeline.title=Pipeline + + +#pageLayout +pageLayout.title=Multi Page Layout +pageLayout.header=Multi Page Layout +pageLayout.pagesPerSheet=Pages per sheet: +pageLayout.submit=Submit + + +#scalePages +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 +certSign.title=Certificate Signing +certSign.header=Sign a PDF with your certificate (Work in progress) +certSign.selectPDF=Select a PDF File for Signing: +certSign.selectKey=Select Your Private Key File (PKCS#8 format, could be .pem or .der): +certSign.selectCert=Select Your Certificate File (X.509 format, could be .pem or .der): +certSign.selectP12=Select Your PKCS#12 Keystore File (.p12 or .pfx) (Optional, If provided, it should contain your private key and certificate): +certSign.certType=Certificate Type +certSign.password=Enter Your Keystore or Private Key Password (If Any): +certSign.showSig=Show Signature +certSign.reason=Reason +certSign.location=Location +certSign.name=Name +certSign.submit=Sign PDF + + +#removeBlanks +removeBlanks.title=Remove Blanks +removeBlanks.header=Remove Blank Pages +removeBlanks.threshold=Pixel Whiteness Threshold: +removeBlanks.thresholdDesc=Threshold for determining how white a white pixel must be to be classed as 'White'. 0 = Black, 255 pure white. +removeBlanks.whitePercent=White Percent (%): +removeBlanks.whitePercentDesc=Percent of page that must be 'white' pixels to be removed +removeBlanks.submit=Remove Blanks + + +#compare +compare.title=Compare +compare.header=Compare PDFs +compare.document.1=Document 1 +compare.document.2=Document 2 +compare.submit=Compare + + +#sign +sign.title=Sign +sign.header=Sign PDFs +sign.upload=Upload Image +sign.draw=Draw Signature +sign.text=Text Input +sign.clear=Clear +sign.add=Add + + +#repair +repair.title=Repair +repair.header=Repair PDFs +repair.submit=Repair + + +#flatten +flatten.title=Flatten +flatten.header=Flatten PDFs +flatten.submit=Flatten + + +#ScannerImageSplit +ScannerImageSplit.selectText.1=Angle Threshold: +ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10). +ScannerImageSplit.selectText.3=Tolerance: +ScannerImageSplit.selectText.4=Determines the range of color variation around the estimated background color (default: 30). +ScannerImageSplit.selectText.5=Minimum Area: +ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000). +ScannerImageSplit.selectText.7=Minimum Contour Area: +ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo +ScannerImageSplit.selectText.9=Border Size: +ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1). + + +#OCR +ocr.title=OCR / Scan Cleanup +ocr.header=Cleanup Scans / OCR (Optical Character Recognition) +ocr.selectText.1=Select languages that are to be detected within the PDF (Ones listed are the ones currently detected): +ocr.selectText.2=Produce text file containing OCR text alongside the OCR'ed PDF +ocr.selectText.3=Correct pages were scanned at a skewed angle by rotating them back into place +ocr.selectText.4=Clean page so its less likely that OCR will find text in background noise. (No output change) +ocr.selectText.5=Clean page so its less likely that OCR will find text in background noise, maintains cleanup in output. +ocr.selectText.6=Ignores pages that have interactive text on them, only OCRs pages that are images +ocr.selectText.7=Force OCR, will OCR Every page removing all original text elements +ocr.selectText.8=Normal (Will error if PDF contains text) +ocr.selectText.9=Additional Settings +ocr.selectText.10=OCR Mode +ocr.selectText.11=Remove images after OCR (Removes ALL images, only useful if part of conversion step) +ocr.selectText.12=Render Type (Advanced) +ocr.help=Please read this documentation on how to use this for other languages and/or use not in docker +ocr.credit=This service uses OCRmyPDF and Tesseract for OCR. +ocr.submit=Process PDF with OCR + + +#extractImages +extractImages.title=Extract Images +extractImages.header=Extract Images +extractImages.selectText=Select image format to convert extracted images to +extractImages.submit=Extract + + +#File to PDF +fileToPDF.title=File to PDF +fileToPDF.header=Convert any file to PDF +fileToPDF.credit=This service uses LibreOffice and Unoconv for file conversion. +fileToPDF.supportedFileTypes=Supported file types should include the below however for a full updated list of supported formats, please refer to the LibreOffice documentation +fileToPDF.submit=Convert to PDF + + +#compress +compress.title=Compress +compress.header=Compress PDF +compress.credit=This service uses Ghostscript for PDF Compress/Optimisation. +compress.selectText.1=Manual Mode - From 1 to 4 +compress.selectText.2=Optimization level: +compress.selectText.3=4 (Terrible for text images) +compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size +compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB) +compress.submit=Compress + + +#Add image +addImage.title=Add Image +addImage.header=Add image to PDF +addImage.everyPage=Every Page? +addImage.upload=Add image +addImage.submit=Add image + + +#merge +merge.title=Merge +merge.header=Merge multiple PDFs (2+) +merge.submit=Merge + + +#pdfOrganiser +pdfOrganiser.title=Page Organiser +pdfOrganiser.header=PDF Page Organiser +pdfOrganiser.submit=Rearrange Pages + + +#multiTool +multiTool.title=PDF Multi Tool +multiTool.header=PDF Multi Tool + + +#pageRemover +pageRemover.title=Page Remover +pageRemover.header=PDF Page remover +pageRemover.pagesToDelete=Pages to delete (Enter a comma-separated list of page numbers) : +pageRemover.submit=Delete Pages + + +#rotate +rotate.title=Rotate PDF +rotate.header=Rotate PDF +rotate.selectAngle=Select rotation angle (in multiples of 90 degrees): +rotate.submit=Rotate + + +#merge +split.title=Split PDF +split.header=Split PDF +split.desc.1=The numbers you select are the page number you wish to do a split on +split.desc.2=As such selecting 1,3,7-8 would split a 10 page document into 6 separate PDFS with: +split.desc.3=Document #1: Page 1 +split.desc.4=Document #2: Page 2 and 3 +split.desc.5=Document #3: Page 4, 5 and 6 +split.desc.6=Document #4: Page 7 +split.desc.7=Document #5: Page 8 +split.desc.8=Document #6: Page 9 and 10 +split.splitPages=Enter pages to split on: +split.submit=Split + + +#merge +imageToPDF.title=Image to PDF +imageToPDF.header=Image to PDF +imageToPDF.submit=Convert +imageToPDF.selectText.1=Stretch to fit +imageToPDF.selectText.2=Auto rotate PDF +imageToPDF.selectText.3=Multi file logic (Only enabled if working with multiple images) +imageToPDF.selectText.4=Merge into single PDF +imageToPDF.selectText.5=Convert to separate PDFs + + +#pdfToImage +pdfToImage.title=PDF to Image +pdfToImage.header=PDF to Image +pdfToImage.selectText=Image Format +pdfToImage.singleOrMultiple=Image result type +pdfToImage.single=Single Big Image +pdfToImage.multi=Multiple Images +pdfToImage.colorType=Colour type +pdfToImage.color=Colour +pdfToImage.grey=Greyscale +pdfToImage.blackwhite=Black and White (May lose data!) +pdfToImage.submit=Convert + + +#addPassword +addPassword.title=Add Password +addPassword.header=Add password (Encrypt) +addPassword.selectText.1=Select PDF to encrypt +addPassword.selectText.2=User Password +addPassword.selectText.3=Encryption Key Length +addPassword.selectText.4=Higher values are stronger, but lower values have better compatibility. +addPassword.selectText.5=Permissions to set (Recommended to be used along with Owner password) +addPassword.selectText.6=Prevent assembly of document +addPassword.selectText.7=Prevent content extraction +addPassword.selectText.8=Prevent extraction for accessibility +addPassword.selectText.9=Prevent filling in form +addPassword.selectText.10=Prevent modification +addPassword.selectText.11=Prevent annotation modification +addPassword.selectText.12=Prevent printing +addPassword.selectText.13=Prevent printing different formats +addPassword.selectText.14=Owner Password +addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers) +addPassword.selectText.16=Restricts the opening of the document itself +addPassword.submit=Encrypt + + +#watermark +watermark.title=Add Watermark +watermark.header=Add Watermark +watermark.selectText.1=Select PDF to add watermark to: +watermark.selectText.2=Watermark Text: +watermark.selectText.3=Font Size: +watermark.selectText.4=Rotation (0-360): +watermark.selectText.5=widthSpacer (Space between each watermark horizontally): +watermark.selectText.6=heightSpacer (Space between each watermark vertically): +watermark.selectText.7=Opacity (0% - 100%): +watermark.submit=Add Watermark + + +#remove-watermark +remove-watermark.title=Remove Watermark +remove-watermark.header=Remove Watermark +remove-watermark.selectText.1=Select PDF to remove watermark from: +remove-watermark.selectText.2=Watermark Text: +remove-watermark.submit=Remove Watermark + + +#Change permissions +permissions.title=Change Permissions +permissions.header=Change Permissions +permissions.warning=Warning to have these permissions be unchangeable it is recommended to set them with a password via the add-password page +permissions.selectText.1=Select PDF to change permissions +permissions.selectText.2=Permissions to set +permissions.selectText.3=Prevent assembly of document +permissions.selectText.4=Prevent content extraction +permissions.selectText.5=Prevent extraction for accessibility +permissions.selectText.6=Prevent filling in form +permissions.selectText.7=Prevent modification +permissions.selectText.8=Prevent annotation modification +permissions.selectText.9=Prevent printing +permissions.selectText.10=Prevent printing different formats +permissions.submit=Change + + +#remove password +removePassword.title=Remove password +removePassword.header=Remove password (Decrypt) +removePassword.selectText.1=Select PDF to Decrypt +removePassword.selectText.2=Password +removePassword.submit=Remove + + +#changeMetadata +changeMetadata.title=Change Metadata +changeMetadata.header=Change Metadata +changeMetadata.selectText.1=Please edit the variables you wish to change +changeMetadata.selectText.2=Delete all metadata +changeMetadata.selectText.3=Show Custom Metadata: +changeMetadata.author=Author: +changeMetadata.creationDate=Creation Date (yyyy/MM/dd HH:mm:ss): +changeMetadata.creator=Creator: +changeMetadata.keywords=Keywords: +changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss): +changeMetadata.producer=Producer: +changeMetadata.subject=Subject: +changeMetadata.title=Title: +changeMetadata.trapped=Trapped: +changeMetadata.selectText.4=Other Metadata: +changeMetadata.selectText.5=Add Custom Metadata Entry +changeMetadata.submit=Change + + +#xlsToPdf +xlsToPdf.title=Excel to PDF +xlsToPdf.header=Excel to PDF +xlsToPdf.selectText.1=Select XLS or XLSX Excel sheet to convert +xlsToPdf.convert=convert + + +#pdfToPDFA +pdfToPDFA.title=PDF To PDF/A +pdfToPDFA.header=PDF To PDF/A +pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion +pdfToPDFA.submit=Convert + + +#PDFToWord +PDFToWord.title=PDF to Word +PDFToWord.header=PDF to Word +PDFToWord.selectText.1=Output file format +PDFToWord.credit=This service uses LibreOffice for file conversion. +PDFToWord.submit=Convert + + +#PDFToPresentation +PDFToPresentation.title=PDF to Presentation +PDFToPresentation.header=PDF to Presentation +PDFToPresentation.selectText.1=Output file format +PDFToPresentation.credit=This service uses LibreOffice for file conversion. +PDFToPresentation.submit=Convert + + +#PDFToText +PDFToText.title=PDF to RTF (Text) +PDFToText.header=PDF to RTF (Text) +PDFToText.selectText.1=Output file format +PDFToText.credit=This service uses LibreOffice for file conversion. +PDFToText.submit=Convert + + +#PDFToHTML +PDFToHTML.title=PDF to HTML +PDFToHTML.header=PDF to HTML +PDFToHTML.credit=This service uses LibreOffice for file conversion. +PDFToHTML.submit=Convert + + +#PDFToXML +PDFToXML.title=PDF to XML +PDFToXML.header=PDF to XML +PDFToXML.credit=This service uses LibreOffice for file conversion. +PDFToXML.submit=Convert \ No newline at end of file From ad4ca1b2d7350781b404da419bb32aeacf5fce65 Mon Sep 17 00:00:00 2001 From: adrielCarmoUFMS <141935947+adrielCarmoUFMS@users.noreply.github.com> Date: Thu, 10 Aug 2023 15:56:15 -0400 Subject: [PATCH 029/301] Update messages_pt_BR.properties Updating the translation of new features to the Portuguese - BR language --- src/main/resources/messages_pt_BR.properties | 771 +++++++++---------- 1 file changed, 357 insertions(+), 414 deletions(-) diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index e615c7304..7112ddf1a 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -26,11 +26,11 @@ text=Texto font=Fonte selectFillter=-- Selecione -- pageNum=Número de página -sizes.small=Small -sizes.medium=Medium -sizes.large=Large -sizes.x-large=X-Large -error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect +sizes.small=Pequeno +sizes.medium=Médio +sizes.large=Grande +sizes.x-large=Muito grande +error.pdfPassword=O documento PDF está protegido por senha e a senha não foi fornecida ou está incorreta ############# @@ -58,210 +58,199 @@ settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados e ############# # HOME-PAGE # ############# -home.desc=Seu melhor utilitário para as necessidades de PDF. - +home.desc=Seu melhor utilitário para suas necessidades de PDF. home.multiTool.title=Multiferramenta de PDF home.multiTool.desc=Mesclar, girar, reorganizar e remover páginas -multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side +multiTool.tags=Multi Ferramenta, Operação Múltipla, Interface do Usuário, Clique e Arraste, Front-end, Lado do Cliente -home.merge.title=mesclar -home.merge.desc=Mescle facilmente vários PDFs em um. -merge.tags=merge,Page operations,Back end,server side +home.merge.title=Mesclar +home.merge.desc=Mesclar facilmente vários PDFs em um só. +merge.tags=mesclar, Operações de Página, Lado do Servidor home.split.title=Dividir home.split.desc=Dividir PDFs em vários documentos -split.tags=Page operations,divide,Multi Page,cut,server side +split.tags=Operações de Página, dividir, Múltiplas Páginas, cortar, Lado do Servidor home.rotate.title=Girar -home.rotate.desc=Gire facilmente seus PDFs. -rotate.tags=server side - +home.rotate.desc=Girar facilmente seus PDFs. +rotate.tags=Lado do Servidor home.imageToPdf.title=Imagem para PDF -home.imageToPdf.desc=Converta uma imagem (PNG, JPEG, GIF) em PDF. -imageToPdf.tags=conversion,img,jpg,picture,photo +home.imageToPdf.desc=Converter uma imagem (PNG, JPEG, GIF) em PDF. +imageToPdf.tags=conversão, img, jpg, imagem, foto -home.pdfToImage.title=PDF para imagem -home.pdfToImage.desc=Converta um PDF em uma imagem. (PNG, JPG, GIF) -pdfToImage.tags=conversion,img,jpg,picture,photo +home.pdfToImage.title=PDF para Imagem +home.pdfToImage.desc=Converter um PDF em uma imagem. (PNG, JPG, GIF) +pdfToImage.tags=conversão, img, jpg, imagem, foto home.pdfOrganiser.title=Organizar -home.pdfOrganiser.desc=Remova/reorganize as páginas em qualquer ordem -pdfOrganiser.tags=duplex,even,odd,sort,move +home.pdfOrganiser.desc=Remover/reorganizar as páginas em qualquer ordem. +pdfOrganiser.tags=duplex, par, ímpar, ordenar, mover +home.addImage.title=Adicionar Imagem +home.addImage.desc=Adicionar uma imagem em um local definido no PDF (trabalho em andamento) +addImage.tags=img, jpg, imagem, foto -home.addImage.title=Adicionar imagem -home.addImage.desc=Adiciona uma imagem em um local definido no PDF (trabalho em andamento) -addImage.tags=img,jpg,picture,photo - -home.watermark.title=Adicione uma Marca d'água -home.watermark.desc=Adicione uma marca d'água personalizada ao seu documento PDF. -watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo - -home.permissions.title=Alterar permissões -home.permissions.desc=Altere as permissões do seu documento PDF -permissions.tags=read,write,edit,print +home.watermark.title=Adicionar Marca d'água +home.watermark.desc=Adicionar uma marca d'água personalizada ao seu documento PDF. +watermark.tags=Texto, repetindo, rótulo, próprio, direitos autorais, marca registrada, img, jpg, imagem, foto +home.permissions.title=Alterar Permissões +home.permissions.desc=Alterar as permissões do seu documento PDF. +permissions.tags=leitura, escrita, edição, impressão home.removePages.title=Remover -home.removePages.desc=Exclua as páginas indesejadas do seu documento PDF. -removePages.tags=Remove pages,delete pages +home.removePages.desc=Excluir as páginas indesejadas do seu documento PDF. +removePages.tags=Remover páginas, excluir páginas -home.addPassword.title=Adicionar senha -home.addPassword.desc=Criptografe seu documento PDF com uma senha. -addPassword.tags=secure,security +home.addPassword.title=Adicionar Senha +home.addPassword.desc=Criptografar seu documento PDF com uma senha. +addPassword.tags=seguro, segurança -home.removePassword.title=Remover senha -home.removePassword.desc=Remova a proteção por senha do seu documento PDF. -removePassword.tags=secure,Decrypt,security,unpassword,delete password +home.removePassword.title=Remover Senha +home.removePassword.desc=Remover a proteção por senha do seu documento PDF. +removePassword.tags=seguro, Descriptografar, segurança, remover senha home.compressPdfs.title=Comprimir -home.compressPdfs.desc=Comprima PDFs para reduzir o tamanho do arquivo. -compressPdfs.tags=squish,small,tiny +home.compressPdfs.desc=Comprimir PDFs para reduzir o tamanho do arquivo. +compressPdfs.tags=compactar, pequeno, mínimo +home.changeMetadata.title=Alterar Metadados +home.changeMetadata.desc=Alterar/remover/adicionar metadados de um documento PDF. +changeMetadata.tags=Título, autor, data, criação, hora, editor, produtor, estatísticas -home.changeMetadata.title=Alterar metadados -home.changeMetadata.desc=Alterar/remover/adicionar metadados de um documento PDF -changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats +home.fileToPDF.title=Converter Arquivo para PDF +home.fileToPDF.desc=Converter praticamente qualquer arquivo em PDF (DOCX, PNG, XLS, PPT, TXT e mais) +fileToPDF.tags=transformação, formato, documento, imagem, slide, texto, conversão, escritório, documentos, word, excel, powerpoint -home.fileToPDF.title=Converter arquivo para PDF -home.fileToPDF.desc=Converta praticamente qualquer arquivo em PDF (DOCX, PNG, XLS, PPT, TXT e mais) -fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint +home.ocr.title=OCR / Limpeza de Digitalizações +home.ocr.desc=A limpeza verifica e detecta texto em imagens de um PDF e o adiciona novamente como texto. +ocr.tags=reconhecimento, texto, imagem, digitalização, leitura, identificação, detecção, editável -home.ocr.title=OCR / Varreduras de limpeza -home.ocr.desc=A limpeza verifica e detecta texto de imagens em um PDF e o adiciona novamente como texto. -ocr.tags=recognition,text,image,scan,read,identify,detection,editable - - -home.extractImages.title=Extrair imagens -home.extractImages.desc=Extrai todas as imagens de um PDF e as salva em zip -extractImages.tags=picture,photo,save,archive,zip,capture,grab +home.extractImages.title=Extrair Imagens +home.extractImages.desc=Extrair todas as imagens de um PDF e salvá-las em um arquivo zip. +extractImages.tags=imagem, foto, salvar, arquivo, zip, captura, coleta home.pdfToPDFA.title=PDF para PDF/A -home.pdfToPDFA.desc=Converta PDF para PDF/A para armazenamento de longo prazo -pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation +home.pdfToPDFA.desc=Converter PDF para o formato PDF/A para armazenamento a longo prazo. +pdfToPDFA.tags=arquivo, longo prazo, padrão, conversão, armazenamento, preservação home.PDFToWord.title=PDF para Word home.PDFToWord.desc=Converter PDF para formatos Word (DOC, DOCX e ODT) -PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile +PDFToWord.tags=doc, docx, odt, word, transformação, formato, conversão, escritório, microsoft, arquivo doc -home.PDFToPresentation.title=PDF para apresentação +home.PDFToPresentation.title=PDF para Apresentação home.PDFToPresentation.desc=Converter PDF para formatos de apresentação (PPT, PPTX e ODP) -PDFToPresentation.tags=slides,show,office,microsoft +PDFToPresentation.tags=slides, apresentação, escritório, microsoft home.PDFToText.title=PDF para Texto/RTF home.PDFToText.desc=Converter PDF em formato de texto ou RTF -PDFToText.tags=richformat,richtextformat,rich text format +PDFToText.tags=formato rico, formato de texto enriquecido, formato de texto rico home.PDFToHTML.title=PDF para HTML home.PDFToHTML.desc=Converter PDF para o formato HTML -PDFToHTML.tags=web content,browser friendly - +PDFToHTML.tags=conteúdo web, compatível com navegador home.PDFToXML.title=PDF para XML home.PDFToXML.desc=Converter PDF para o formato XML -PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert +PDFToXML.tags=extração-de-dados,conteúdo-estruturado,interoperabilidade,transformação,converter -home.ScannerImageSplit.title=Detectar/dividir fotos digitalizadas -home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma foto/PDF -ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize +home.ScannerImageSplit.title=Detectar/Dividir Fotos Digitalizadas +home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma imagem/PDF digitalizado +ScannerImageSplit.tags=separar,detecção-automática,digitalizações,foto-múltipla,organizar -home.sign.title=Sinal -home.sign.desc=Adiciona assinatura ao PDF por desenho, texto ou imagem -sign.tags=authorize,initials,drawn-signature,text-sign,image-signature +home.sign.title=Assinar +home.sign.desc=Adicionar assinatura ao PDF por desenho, texto ou imagem +sign.tags=autorizar,iniciais,assinatura-desenhada,assinatura-de-texto,assinatura-de-imagem -home.flatten.title=achatar -home.flatten.desc=Remova todos os elementos e formulários interativos de um PDF -flatten.tags=static,deactivate,non-interactive,streamline +home.flatten.title=Achatar +home.flatten.desc=Remover todos os elementos e formulários interativos de um PDF +flatten.tags=estático,desativar,não-interativo,otimizar home.repair.title=Reparar -home.repair.desc=Tenta reparar um PDF corrompido/quebrado -repair.tags=fix,restore,correction,recover +home.repair.desc=Tentar reparar um PDF corrompido/quebrado +repair.tags=corrigir,restaurar,correção,recuperar -home.removeBlanks.title=Remover páginas em branco -home.removeBlanks.desc=Detecta e remove páginas em branco de um documento -removeBlanks.tags=cleanup,streamline,non-content,organize +home.removeBlanks.title=Remover Páginas em Branco +home.removeBlanks.desc=Detectar e remover páginas em branco de um documento +removeBlanks.tags=limpeza,otimização,sem-conteúdo,organizar home.compare.title=Comparar -home.compare.desc=Compara e mostra as diferenças entre 2 documentos PDF -compare.tags=differentiate,contrast,changes,analysis +home.compare.desc=Comparar e mostrar as diferenças entre 2 documentos PDF +compare.tags=diferenciar,contraste,mudanças,análise -home.certSign.title=Assinar com certificado -home.certSign.desc=Assina um PDF com um Certificado/Chave (PEM/P12) -certSign.tags=authenticate,PEM,P12,official,encrypt +home.certSign.title=Assinar com Certificado +home.certSign.desc=Assinar um PDF com um Certificado/Chave (PEM/P12) +certSign.tags=autenticar,PEM,P12,oficial,criptografar -home.pageLayout.title=Multi-Page Layout -home.pageLayout.desc=Merge multiple pages of a PDF document into a single page -pageLayout.tags=merge,composite,single-view,organize +home.pageLayout.title=Layout de Múltiplas Páginas +home.pageLayout.desc=Mesclar várias páginas de um documento PDF em uma única página +pageLayout.tags=mesclar,composto,vista-única,organizar -home.scalePages.title=Adjust page size/scale -home.scalePages.desc=Change the size/scale of page and/or its contents. -scalePages.tags=resize,modify,dimension,adapt +home.scalePages.title=Ajustar Tamanho/Escala de Página +home.scalePages.desc=Alterar o tamanho/escala da página e/ou seu conteúdo. +scalePages.tags=redimensionar,modificar,dimensão,adaptar -home.pipeline.title=Pipeline (Advanced) -home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts -pipeline.tags=automate,sequence,scripted,batch-process +home.pipeline.title=Pipeline (Avançado) +home.pipeline.desc=Executar várias ações em PDFs definindo scripts de pipeline +pipeline.tags=automatizar,sequência,scriptado,processo-em-lote -home.add-page-numbers.title=Add Page Numbers -home.add-page-numbers.desc=Add Page numbers throughout a document in a set location -add-page-numbers.tags=paginate,label,organize,index +home.add-page-numbers.title=Adicionar Números de Página +home.add-page-numbers.desc=Adicionar números de página em todo o documento em um local definido +add-page-numbers.tags=paginar,rotular,organizar,índice -home.auto-rename.title=Auto Rename PDF File -home.auto-rename.desc=Auto renames a PDF file based on its detected header -auto-rename.tags=auto-detect,header-based,organize,relabel +home.auto-rename.title=Renomear Automaticamente o Arquivo PDF +home.auto-rename.desc=Renomeia automaticamente um arquivo PDF com base no cabeçalho detectado +auto-rename.tags=detecção-automática,baseado-em-cabeçalho,organizar,relabel -home.adjust-contrast.title=Adjust Colors/Contrast -home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF -adjust-contrast.tags=color-correction,tune,modify,enhance +home.adjust-contrast.title=Ajustar Cores/Contraste +home.adjust-contrast.desc=Ajustar Contraste, Saturação e Brilho de um PDF +adjust-contrast.tags=correção-de-cor,ajustar,modificar,realçar -home.crop.title=Crop PDF -home.crop.desc=Crop a PDF to reduce its size (maintains text!) -crop.tags=trim,shrink,edit,shape +home.crop.title=Cortar PDF +home.crop.desc=Cortar um PDF para reduzir o tamanho (mantém o texto!) +crop.tags=aparar,encolher,editar,formato -home.autoSplitPDF.title=Auto Split Pages -home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code -autoSplitPDF.tags=QR-based,separate,scan-segment,organize +home.autoSplitPDF.title=Divisão Automática de Páginas +home.autoSplitPDF.desc=Dividir automaticamente um PDF digitalizado com separador de páginas físicas QR Code +autoSplitPDF.tags=baseado-em-QR,separar,segmento-de-digitalização,organizar -home.sanitizePdf.title=Sanitize -home.sanitizePdf.desc=Remove scripts and other elements from PDF files -sanitizePdf.tags=clean,secure,safe,remove-threats +home.sanitizePdf.title=Sanitizar +home.sanitizePdf.desc=Remover scripts e outros elementos de arquivos PDF +sanitizePdf.tags=limpar,seguro,protegido,remover-ameaças -home.URLToPDF.title=URL/Website To PDF -home.URLToPDF.desc=Converts any http(s)URL to PDF -URLToPDF.tags=web-capture,save-page,web-to-doc,archive +home.URLToPDF.title=URL/Site para PDF +home.URLToPDF.desc=Converte qualquer URL http(s) para PDF +URLToPDF.tags=captura-de-web,salvar-página,web-para-doc,arquivar -home.HTMLToPDF.title=HTML to PDF -home.HTMLToPDF.desc=Converts any HTML file or zip to PDF -HTMLToPDF.tags=markup,web-content,transformation,convert +home.HTMLToPDF.title=HTML para PDF +home.HTMLToPDF.desc=Converte qualquer arquivo HTML ou zip para PDF +HTMLToPDF.tags=marcação,conteúdo-web,transformação,converter +home.MarkdownToPDF.title=Markdown para PDF +home.MarkdownToPDF.desc=Converte qualquer arquivo Markdown para PDF +MarkdownToPDF.tags=marcação,conteúdo-web,transformação,converter -home.MarkdownToPDF.title=Markdown to PDF -home.MarkdownToPDF.desc=Converts any Markdown file to PDF -MarkdownToPDF.tags=markup,web-content,transformation,convert +home.getPdfInfo.title=Obter TODAS as Informações de um PDF +home.getPdfInfo.desc=Obtém todas as informações possíveis de um PDF +getPdfInfo.tags=informações,dados,estatísticas +home.extractPage.title=Extrair Página(s) +home.extractPage.desc=Extrai páginas selecionadas de um PDF +extractPage.tags=extrair -home.getPdfInfo.title=Get ALL Info on PDF -home.getPdfInfo.desc=Grabs any and all information possible on PDFs -getPdfInfo.tags=infomation,data,stats,statistics - - -home.extractPage.title=Extract page(s) -home.extractPage.desc=Extracts select pages from PDF -extractPage.tags=extract - - -home.PdfToSinglePage.title=PDF to Single Large Page -home.PdfToSinglePage.desc=Merges all PDF pages into one large single page -PdfToSinglePage.tags=single page +home.PdfToSinglePage.title=PDF para Página Única Grande +home.PdfToSinglePage.desc=Combina todas as páginas de um PDF em uma única página grande +PdfToSinglePage.tags=página única ########################## ### TODO: Translate ### ########################## -home.showJS.title=Show Javascript -home.showJS.desc=Searches and displays any JS injected into a PDF -showJS.tags=JS +home.showJS.title=Mostrar Javascript +home.showJS.desc=Procura e exibe qualquer JavaScript injetado em um PDF +showJS.tags=JavaScript ########################### # # @@ -272,158 +261,140 @@ showJS.tags=JS ########################## ### TODO: Translate ### ########################## -showJS.title=Show Javascript -showJS.header=Show Javascript -showJS.downloadJS=Download Javascript -showJS.submit=Show - +showJS.title=Exibir JavaScript +showJS.header=Exibir JavaScript +showJS.downloadJS=Download do JavaScript +showJS.submit=Exibir #pdfToSinglePage -pdfToSinglePage.title=PDF To Single Page -pdfToSinglePage.header=PDF To Single Page -pdfToSinglePage.submit=Convert To Single Page - +pdfToSinglePage.title=PDF para Página Única +pdfToSinglePage.header=PDF para Página Única +pdfToSinglePage.submit=Converter para Página Única #pageExtracter -pageExtracter.title=Extract Pages -pageExtracter.header=Extract Pages -pageExtracter.submit=Extract - +pageExtracter.title=Extrair Páginas +pageExtracter.header=Extrair Páginas +pageExtracter.submit=Extrair #getPdfInfo -getPdfInfo.title=Get Info on PDF -getPdfInfo.header=Get Info on PDF -getPdfInfo.submit=Get Info +getPdfInfo.title=Obter Informações do PDF +getPdfInfo.header=Obter Informações do PDF +getPdfInfo.submit=Obter Informações getPdfInfo.downloadJson=Download JSON - #markdown-to-pdf -MarkdownToPDF.title=Markdown To PDF -MarkdownToPDF.header=Markdown To PDF -MarkdownToPDF.submit=Convert -MarkdownToPDF.help=Work in progress -MarkdownToPDF.credit=Uses WeasyPrint - - +MarkdownToPDF.title=Markdown para PDF +MarkdownToPDF.header=Markdown para PDF +MarkdownToPDF.submit=Converter +MarkdownToPDF.help=Trabalho em andamento +MarkdownToPDF.credit=Usa o WeasyPrint #url-to-pdf -URLToPDF.title=URL To PDF -URLToPDF.header=URL To PDF -URLToPDF.submit=Convert -URLToPDF.credit=Uses WeasyPrint - +URLToPDF.title=URL para PDF +URLToPDF.header=URL para PDF +URLToPDF.submit=Converter +URLToPDF.credit=Usa o WeasyPrint #html-to-pdf -HTMLToPDF.title=HTML To PDF -HTMLToPDF.header=HTML To PDF -HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required -HTMLToPDF.submit=Convert -HTMLToPDF.credit=Uses WeasyPrint - +HTMLToPDF.title=HTML para PDF +HTMLToPDF.header=HTML para PDF +HTMLToPDF.help=Aceita arquivos HTML e ZIPs contendo html/css/imagens etc necessários +HTMLToPDF.submit=Converter +HTMLToPDF.credit=Usa o WeasyPrint #sanitizePDF -sanitizePDF.title=Sanitize PDF -sanitizePDF.header=Sanitize a PDF file -sanitizePDF.selectText.1=Remove JavaScript actions -sanitizePDF.selectText.2=Remove embedded files -sanitizePDF.selectText.3=Remove metadata -sanitizePDF.selectText.4=Remove links -sanitizePDF.selectText.5=Remove fonts -sanitizePDF.submit=Sanitize PDF - +sanitizePDF.title=Sanitizar PDF +sanitizePDF.header=Sanitizar um arquivo PDF +sanitizePDF.selectText.1=Remover ações de JavaScript +sanitizePDF.selectText.2=Remover arquivos embutidos +sanitizePDF.selectText.3=Remover metadados +sanitizePDF.selectText.4=Remover links +sanitizePDF.selectText.5=Remover fontes +sanitizePDF.submit=Sanitizar PDF #addPageNumbers -addPageNumbers.title=Add Page Numbers -addPageNumbers.header=Add Page Numbers -addPageNumbers.selectText.1=Select PDF file: -addPageNumbers.selectText.2=Margin Size -addPageNumbers.selectText.3=Position -addPageNumbers.selectText.4=Starting Number -addPageNumbers.selectText.5=Pages to Number -addPageNumbers.selectText.6=Custom Text -addPageNumbers.submit=Add Page Numbers - +addPageNumbers.title=Adicionar Números de Página +addPageNumbers.header=Adicionar Números de Página +addPageNumbers.selectText.1=Selecionar arquivo PDF: +addPageNumbers.selectText.2=Tamanho da Margem +addPageNumbers.selectText.3=Posição +addPageNumbers.selectText.4=Número Inicial +addPageNumbers.selectText.5=Páginas a Numerar +addPageNumbers.selectText.6=Texto Personalizado +addPageNumbers.submit=Adicionar Números de Página #auto-rename -auto-rename.title=Auto Rename -auto-rename.header=Auto Rename PDF -auto-rename.submit=Auto Rename - +auto-rename.title=Rename Automático +auto-rename.header=Rename Automático de PDF +auto-rename.submit=Rename Automático #adjustContrast -adjustContrast.title=Adjust Contrast -adjustContrast.header=Adjust Contrast -adjustContrast.contrast=Contrast: -adjustContrast.brightness=Brightness: -adjustContrast.saturation=Saturation: +adjustContrast.title=Ajustar Contraste +adjustContrast.header=Ajustar Contraste +adjustContrast.contrast=Contraste: +adjustContrast.brightness=Brilho: +adjustContrast.saturation=Saturação: adjustContrast.download=Download - #crop -crop.title=Crop -crop.header=Crop Image -crop.submit=Submit - +crop.title=Cortar +crop.header=Cortar Imagem +crop.submit=Enviar #autoSplitPDF -autoSplitPDF.title=Auto Split PDF -autoSplitPDF.header=Auto Split PDF -autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed. -autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine). -autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them. -autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest. -autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document. -autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers: -autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning) -autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf' -autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf' -autoSplitPDF.submit=Submit - +autoSplitPDF.title=Divisão Automática de PDF +autoSplitPDF.header=Divisão Automática de PDF +autoSplitPDF.description=Imprima, insira, digitalize, faça o upload e deixe que a gente divida seus documentos automaticamente. Nenhuma classificação manual necessária. +autoSplitPDF.selectText.1=Imprima algumas folhas divisórias abaixo (preto e branco está bom). +autoSplitPDF.selectText.2=Digitalize todos os seus documentos de uma vez, inserindo a folha divisória entre eles. +autoSplitPDF.selectText.3=Faça o upload do único arquivo PDF grande digitalizado e deixe o Stirling PDF cuidar do resto. +autoSplitPDF.selectText.4=As páginas divisórias são detectadas e removidas automaticamente, garantindo um documento final organizado. +autoSplitPDF.formPrompt=Enviar PDF contendo folhas divisórias Stirling-PDF: +autoSplitPDF.duplexMode=Modo Duplex (Digitalização frente e verso) +autoSplitPDF.dividerDownload1=Download 'Folha Divisória Automática (mínima).pdf' +autoSplitPDF.dividerDownload2=Download 'Folha Divisória Automática (com instruções).pdf' +autoSplitPDF.submit=Enviar #pipeline pipeline.title=Pipeline #pageLayout -pageLayout.title=Multi Page Layout -pageLayout.header=Multi Page Layout -pageLayout.pagesPerSheet=Pages per sheet: -pageLayout.submit=Submit - +pageLayout.title=Layout de Múltiplas Páginas +pageLayout.header=Layout de Múltiplas Páginas +pageLayout.pagesPerSheet=Páginas por folha: +pageLayout.submit=Enviar #scalePages -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 - +scalePages.title=Ajustar Tamanho/Escala da Página +scalePages.header=Ajustar Tamanho/Escala da Página +scalePages.pageSize=Tamanho de uma página do documento. +scalePages.scaleFactor=Fator de zoom (corte) de uma página. +scalePages.submit=Enviar #certSign -certSign.title=Assinatura de certificado -certSign.header=Assine um PDF com seu certificado (Trabalho em andamento) +certSign.title=Assinatura com Certificado +certSign.header=Assine um PDF com o seu certificado (Em desenvolvimento) certSign.selectPDF=Selecione um arquivo PDF para assinatura: -certSign.selectKey=Selecione seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der): -certSign.selectCert=Selecione seu arquivo de certificado (formato X.509, pode ser .pem ou .der): -certSign.selectP12=Selecione seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter sua chave privada e certificado): -certSign.certType=tipo de certificado -certSign.password=Digite seu armazenamento de chave ou senha de chave privada (se houver): -certSign.showSig=Mostrar assinatura +certSign.selectKey=Selecione o seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der): +certSign.selectCert=Selecione o seu arquivo de certificado (formato X.509, pode ser .pem ou .der): +certSign.selectP12=Selecione o seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter a sua chave privada e certificado): +certSign.certType=Tipo de Certificado +certSign.password=Digite a senha do seu armazenamento de chave ou chave privada (se aplicável): +certSign.showSig=Mostrar Assinatura certSign.reason=Razão certSign.location=Localização certSign.name=Nome certSign.submit=Assinar PDF - #removeBlanks -removeBlanks.title=Remover espaços em branco -removeBlanks.header=Remover páginas em branco -removeBlanks.threshold=Limite: -removeBlanks.thresholdDesc=Limiar para determinar quão branco um pixel branco deve ser -removeBlanks.whitePercent=Porcentagem branca (%): +removeBlanks.title=Remover Páginas em Branco +removeBlanks.header=Remover Páginas em Branco +removeBlanks.threshold=Limiar: +removeBlanks.thresholdDesc=Limiar para determinar o quão branco um pixel branco deve ser +removeBlanks.whitePercent=Porcentagem de Branco (%): removeBlanks.whitePercentDesc=Porcentagem da página que deve ser branca para ser removida -removeBlanks.submit=Remover espaços em branco - +removeBlanks.submit=Remover Páginas em Branco #compare compare.title=Comparar @@ -432,28 +403,24 @@ compare.document.1=Documento 1 compare.document.2=Documento 2 compare.submit=Comparar - #sign -sign.title=Sinal +sign.title=Assinar sign.header=Assinar PDFs sign.upload=Enviar Imagem sign.draw=Desenhar Assinatura -sign.text=Entrada de texto -sign.clear=Claro +sign.text=Inserir Texto +sign.clear=Limpar sign.add=Adicionar - #repair repair.title=Reparar repair.header=Reparar PDFs repair.submit=Reparar - #flatten -flatten.title=achatar +flatten.title=Achatar flatten.header=Achatar PDFs -flatten.submit=achatar - +flatten.submit=Achatar #ScannerImageSplit ScannerImageSplit.selectText.1=Limite de Ângulo: @@ -469,266 +436,242 @@ ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida #OCR -ocr.title=OCR / Limpeza de digitalização -ocr.header=Varreduras de limpeza / OCR (reconhecimento óptico de caracteres) -ocr.selectText.1=Selecione os idiomas que devem ser detectados no PDF (os listados são os atualmente detectados): -ocr.selectText.2=Produzir arquivo de texto contendo texto OCR ao lado do PDF com OCR -ocr.selectText.3=As páginas corretas foram digitalizadas em um ângulo inclinado girando-as de volta ao lugar -ocr.selectText.4=Limpe a página para que seja menos provável que o OCR encontre o texto no ruído de fundo. (Sem mudança de saída) -ocr.selectText.5=Limpe a página para que seja menos provável que o OCR encontre texto no ruído de fundo, mantendo a limpeza na saída. -ocr.selectText.6=Ignora as páginas que contêm texto interativo, apenas as páginas de OCR que são imagens -ocr.selectText.7=Forçar OCR, irá OCR Todas as páginas removendo todos os elementos de texto originais -ocr.selectText.8=Normal (será um erro se o PDF contiver texto) +ocr.title=OCR / Limpeza de Digitalização +ocr.header=OCR / Limpeza de Digitalização (Reconhecimento Óptico de Caracteres) +ocr.selectText.1=Selecione os idiomas a serem detectados no PDF (os listados são os atualmente detectados): +ocr.selectText.2=Criar um arquivo de texto contendo o texto OCR ao lado do PDF com OCR +ocr.selectText.3=Páginas corretamente digitalizadas em um ângulo inclinado, gire-as de volta à posição original +ocr.selectText.4=Limpar a página para reduzir a probabilidade de o OCR encontrar texto no ruído de fundo (sem alteração na saída) +ocr.selectText.5=Limpar a página para reduzir a probabilidade de o OCR encontrar texto no ruído de fundo, mantendo a limpeza na saída. +ocr.selectText.6=Ignorar páginas com texto interativo, processar apenas as páginas de OCR que são imagens +ocr.selectText.7=Forçar OCR, executar OCR em todas as páginas, removendo todos os elementos de texto originais +ocr.selectText.8=Normal (gerará um erro se o PDF já contiver texto) ocr.selectText.9=Configurações adicionais ocr.selectText.10=Modo OCR -ocr.selectText.11=Remova as imagens após o OCR (remove TODAS as imagens, útil apenas se fizer parte da etapa de conversão) -ocr.selectText.12=Tipo de renderização (avançado) -ocr.help=Por favor, leia esta documentação sobre como usar isso para outros idiomas e/ou não usar no docker +ocr.selectText.11=Remover imagens após o OCR (remove TODAS as imagens, útil apenas como parte do processo de conversão) +ocr.help=Por favor, leia a documentação sobre como usar isso para outros idiomas e/ou fora do ambiente Docker ocr.credit=Este serviço usa OCRmyPDF e Tesseract para OCR. ocr.submit=Processar PDF com OCR - #extractImages extractImages.title=Extrair Imagens extractImages.header=Extrair Imagens -extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas em +extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas extractImages.submit=Extrair - #File to PDF fileToPDF.title=Arquivo para PDF -fileToPDF.header=Converta qualquer arquivo para PDF -fileToPDF.credit=Este serviço usa LibreOffice e Unoconv para conversão de arquivos. -fileToPDF.supportedFileTypes=Os tipos de arquivo suportados devem incluir o abaixo, no entanto, para obter uma lista atualizada completa de formatos suportados, consulte a documentação do LibreOffice +fileToPDF.header=Converter Qualquer Arquivo para PDF +fileToPDF.credit=Este serviço usa o LibreOffice e o Unoconv para conversão de arquivos. +fileToPDF.supportedFileTypes=Os tipos de arquivo suportados devem incluir os listados abaixo. No entanto, para obter uma lista atualizada completa dos formatos suportados, consulte a documentação do LibreOffice. fileToPDF.submit=Converter para PDF - #compress compress.title=Comprimir compress.header=Comprimir PDF compress.credit=Este serviço usa o Ghostscript para compressão/otimização de PDF. compress.selectText.1=Modo Manual - De 1 a 4 -compress.selectText.2=Nível de otimização: -compress.selectText.3=4 (Péssimo para imagens de texto) -compress.selectText.4=Modo automático - Auto ajusta a qualidade para obter o tamanho exato do PDF -compress.selectText.5=Tamanho esperado do PDF (por exemplo, 25 MB, 10,8 MB, 25 KB) +compress.selectText.2=Nível de Otimização: +compress.selectText.3=4 (Pior para imagens de texto) +compress.selectText.4=Modo Automático - Ajusta automaticamente a qualidade para atingir o tamanho exato do PDF +compress.selectText.5=Tamanho Esperado do PDF (por exemplo, 25 MB, 10,8 MB, 25 KB) compress.submit=Comprimir - #Add image -addImage.title=Adicionar imagem -addImage.header=Adicionar imagem ao PDF -addImage.everyPage=Cada página? -addImage.upload=Adicionar imagem -addImage.submit=Adicionar imagem - +addImage.title=Adicionar Imagem +addImage.header=Adicionar Imagem ao PDF +addImage.everyPage=Para cada página? +addImage.upload=Enviar Imagem +addImage.submit=Adicionar Imagem #merge -merge.title=mesclar -merge.header=Mesclar vários PDFs (2+) -merge.submit=mesclar - +merge.title=Mesclar +merge.header=Mesclar Vários PDFs (2+) +merge.submit=Mesclar #pdfOrganiser -pdfOrganiser.title=Organizador de página -pdfOrganiser.header=Organizador de páginas PDF -pdfOrganiser.submit=Reorganizar páginas - +pdfOrganiser.title=Organizador de Páginas +pdfOrganiser.header=Organizador de Páginas PDF +pdfOrganiser.submit=Reorganizar Páginas #multiTool multiTool.title=Multiferramenta de PDF multiTool.header=Multiferramenta de PDF - #pageRemover -pageRemover.title=Removedor de página -pageRemover.header=Removedor de página PDF -pageRemover.pagesToDelete=Páginas a serem excluídas (digite uma lista separada por vírgulas de números de página): -pageRemover.submit=Excluir páginas - +pageRemover.title=Remover Página +pageRemover.header=Remover Páginas do PDF +pageRemover.pagesToDelete=Páginas a serem excluídas (insira uma lista separada por vírgulas de números de página): +pageRemover.submit=Excluir Páginas #rotate rotate.title=Girar PDF rotate.header=Girar PDF -rotate.selectAngle=Selecione o ângulo de rotação (em múltiplos de 90 graus): +rotate.selectAngle=Selecione o ângulo de rotação (múltiplos de 90 graus): rotate.submit=Girar - #merge -split.title=PDF dividido -split.header=PDF dividido -split.desc.1=Os números que você selecionar são o número da página na qual você deseja fazer uma divisão -split.desc.2=Assim, selecionar 1,3,7-8 dividiria um documento de 10 páginas em 6 PDFS separados com: -split.desc.3=Documento nº 1: página 1 -split.desc.4=Documento nº 2: páginas 2 e 3 -split.desc.5=Documento nº 3: Página 4, 5 e 6 -split.desc.6=Documento nº 4: página 7 -split.desc.7=Documento nº 5: página 8 -split.desc.8=Documento nº 6: páginas 9 e 10 -split.splitPages=Digite as páginas para dividir: +split.title=Dividir PDF +split.header=Dividir PDF +split.desc.1=Os números selecionados correspondem às páginas onde você deseja fazer a divisão. +split.desc.2,3,4,5,6,7,8=Por exemplo, selecionar 1,3,7-8 dividirá um documento de 10 páginas em 6 PDFs separados da seguinte forma: +split.desc.2=Documento 1: Página 1 +split.desc.3=Documento 2: Páginas 2 e 3 +split.desc.4=Documento 3: Páginas 4, 5 e 6 +split.desc.5=Documento 4: Página 7 +split.desc.6=Documento 5: Página 8 +split.desc.7=Documento 6: Páginas 9 e 10 +split.splitPages=Digite as páginas para a divisão: split.submit=Dividir - #merge imageToPDF.title=Imagem para PDF -imageToPDF.header=Imagem para PDF +imageToPDF.header=Converter Imagem para PDF imageToPDF.submit=Converter -imageToPDF.selectText.1=Esticar para caber -imageToPDF.selectText.2=Girar PDF automaticamente -imageToPDF.selectText.3=Lógica de vários arquivos (Ativado apenas se estiver trabalhando com várias imagens) -imageToPDF.selectText.4=Mesclar em um único PDF -imageToPDF.selectText.5=Converter em PDFs separados - - +imageToPDF.selectText.1=Esticar para Ajustar +imageToPDF.selectText.2=Girar Automaticamente +imageToPDF.selectText.3=Lógica de Vários Arquivos (Ativada apenas ao trabalhar com várias imagens) +imageToPDF.selectText.4=Mesclar em um Único PDF +imageToPDF.selectText.5=Converter em PDFs Separados + #pdfToImage -pdfToImage.title=PDF para imagem -pdfToImage.header=PDF para imagem -pdfToImage.selectText=Formato de imagem -pdfToImage.singleOrMultiple=Tipo de resultado de imagem -pdfToImage.single=Imagem grande única -pdfToImage.multi=Imagens múltiplas -pdfToImage.colorType=tipo de cor -pdfToImage.color=Cor -pdfToImage.grey=Escala de cinza -pdfToImage.blackwhite=Preto e branco (pode perder dados!) +pdfToImage.title=PDF para Imagem +pdfToImage.header=Converter PDF para Imagem +pdfToImage.selectText=Formato de Imagem +pdfToImage.singleOrMultiple=Tipo de Resultado de Imagem +pdfToImage.single=Única Imagem Grande +pdfToImage.multi=Múltiplas Imagens +pdfToImage.colorType=Tipo de Cor +pdfToImage.color=Colorida +pdfToImage.grey=Escala de Cinza +pdfToImage.blackwhite=Preto e Branco (pode resultar em perda de dados!) pdfToImage.submit=Converter #addPassword -addPassword.title=Adicionar senha -addPassword.header=Adicionar senha (Criptografar) -addPassword.selectText.1=Selecione PDF para criptografar +addPassword.title=Adicionar Senha +addPassword.header=Adicionar Senha (Criptografar) +addPassword.selectText.1=Selecione o PDF para Criptografar addPassword.selectText.2=Senha -addPassword.selectText.3=Comprimento da chave de criptografia -addPassword.selectText.4=Valores mais altos são mais fortes, mas valores mais baixos têm melhor compatibilidade. -addPassword.selectText.5=Permissões para definir -addPassword.selectText.6=Impedir a montagem do documento -addPassword.selectText.7=Impedir a extração de conteúdo -addPassword.selectText.8=Impedir a extração para acessibilidade -addPassword.selectText.9=Impedir o preenchimento do formulário -addPassword.selectText.10=Impedir modificação -addPassword.selectText.11=Impedir a modificação da anotação -addPassword.selectText.12=Impedir a impressão -addPassword.selectText.13=Impedir a impressão de formatos diferentes -addPassword.selectText.14=Owner Password -addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers) -addPassword.selectText.16=Restricts the opening of the document itself -addPassword.submit=criptografar - +addPassword.selectText.3=Tamanho da Chave de Criptografia +addPassword.selectText.4=Valores mais altos são mais seguros, mas valores mais baixos são mais compatíveis. +addPassword.selectText.5=Permissões para Definir +addPassword.selectText.6=Impedir Montagem do Documento +addPassword.selectText.7=Impedir Extração de Conteúdo +addPassword.selectText.8=Impedir Extração para Acessibilidade +addPassword.selectText.9=Impedir Preenchimento de Formulário +addPassword.selectText.10=Impedir Modificação +addPassword.selectText.11=Impedir Modificação de Anotação +addPassword.selectText.12=Impedir Impressão +addPassword.selectText.13=Impedir Impressão de Formatos Diferentes +addPassword.selectText.14=Senha do Proprietário +addPassword.selectText.15=Restringe o que pode ser feito com o documento após a abertura (nem todos os leitores dão suporte a isso) +addPassword.selectText.16=Restringe a abertura do próprio documento +addPassword.submit=Criptografar #watermark -watermark.title=Adicione uma Marca d'água -watermark.header=Adicione uma Marca d'água -watermark.selectText.1=Selecione PDF para adicionar marca d'água a: -watermark.selectText.2=Texto da marca d'água: -watermark.selectText.3=Tamanho da fonte: -watermark.selectText.4=Rotação (0-360): -watermark.selectText.5=widthSpacer (espaço entre cada marca d'água horizontalmente): -watermark.selectText.6=heightSpacer (espaço entre cada marca d'água verticalmente): -watermark.selectText.7=Opacidade (0% - 100%): -watermark.submit=Adicione uma Marca d'água - +watermark.title=Adicionar Marca d'Água +watermark.header=Adicionar Marca d'Água +watermark.selectText.1=Selecione o PDF para Adicionar a Marca d'Água +watermark.selectText.2=Texto da Marca d'Água +watermark.selectText.3=Tamanho da Fonte +watermark.selectText.4=Rotação (0-360) +watermark.selectText.5=Espaçamento Horizontal (widthSpacer) +watermark.selectText.6=Espaçamento Vertical (heightSpacer) +watermark.selectText.7=Opacidade (0% - 100%) +watermark.submit=Adicionar Marca d'Água #remove-watermark -remove-watermark.title=Remover marca d'água -remove-watermark.header=Remover marca d'água -remove-watermark.selectText.1=Selecione PDF para remover a marca d'água de: -remove-watermark.selectText.2=Texto da marca d'água: -remove-watermark.submit=Remover marca d'água - +remove-watermark.title=Remover Marca d'Água +remove-watermark.header=Remover Marca d'Água +remove-watermark.selectText.1=Selecione o PDF para Remover a Marca d'Água +remove-watermark.selectText.2=Texto da Marca d'Água +remove-watermark.submit=Remover Marca d'Água #Change permissions -permissions.title=Alterar permissões -permissions.header=Alterar permissões -permissions.warning=Aviso para que essas permissões sejam inalteráveis, é recomendável defini-las com uma senha por meio da página adicionar senha -permissions.selectText.1=Selecione o PDF para alterar as permissões -permissions.selectText.2=Permissões para definir -permissions.selectText.3=Impedir a montagem do documento -permissions.selectText.4=Impedir a extração de conteúdo -permissions.selectText.5=Impedir extração para acessibilidade -permissions.selectText.6=Impedir o preenchimento do formulário -permissions.selectText.7=Impedir modificações -permissions.selectText.8=Impedir a modificação da anotação -permissions.selectText.9=Impedir a impressão -permissions.selectText.10=Impedir a impressão de formatos diferentes +permissions.title=Alterar Permissões +permissions.header=Alterar Permissões +permissions.warning=Nota: Para tornar essas permissões inalteráveis, é recomendável defini-las com uma senha através da página "Adicionar Senha". +permissions.selectText.1=Selecione o PDF para Alterar as Permissões +permissions.selectText.2=Permissões para Definir +permissions.selectText.3=Impedir Montagem do Documento +permissions.selectText.4=Impedir Extração de Conteúdo +permissions.selectText.5=Impedir Extração para Acessibilidade +permissions.selectText.6=Impedir Preenchimento de Formulário +permissions.selectText.7=Impedir Modificações +permissions.selectText.8=Impedir Modificação de Anotação +permissions.selectText.9=Impedir Impressão +permissions.selectText.10=Impedir Impressão de Formatos Diferentes permissions.submit=Mudar - #remove password -removePassword.title=Remover senha -removePassword.header=Remover senha (Descriptografar) -removePassword.selectText.1=Selecione PDF para descriptografar +removePassword.title=Remover Senha +removePassword.header=Remover Senha (Descriptografar) +removePassword.selectText.1=Selecione o PDF para Descriptografar removePassword.selectText.2=Senha removePassword.submit=Remover #changeMetadata -changeMetadata.title=Título: -changeMetadata.header=Alterar metadados -changeMetadata.selectText.1=Edite as variáveis que deseja alterar -changeMetadata.selectText.2=Excluir todos os metadados -changeMetadata.selectText.3=Mostrar metadados personalizados: +changeMetadata.title=Alterar Metadados +changeMetadata.header=Alterar Metadados +changeMetadata.selectText.1=Edite as Variáveis que Deseja Alterar +changeMetadata.selectText.2=Excluir Todos os Metadados +changeMetadata.selectText.3=Mostrar Metadados Personalizados changeMetadata.author=Autor: changeMetadata.creationDate=Data de Criação (aaaa/MM/dd HH:mm:ss): -changeMetadata.creator=O Criador: +changeMetadata.creator=Criador: changeMetadata.keywords=Palavras-chave: -changeMetadata.modDate=Data de modificação (aaaa/MM/dd HH:mm:ss): +changeMetadata.modDate=Data de Modificação (aaaa/MM/dd HH:mm:ss): changeMetadata.producer=Produtor: changeMetadata.subject=Assunto: changeMetadata.title=Título: -changeMetadata.trapped=Encurralado: -changeMetadata.selectText.4=Outros metadados: -changeMetadata.selectText.5=Adicionar entrada de metadados personalizados +changeMetadata.trapped=Trapped: +changeMetadata.selectText.4=Outros Metadados +changeMetadata.selectText.5=Adicionar Entrada de Metadados Personalizados changeMetadata.submit=Mudar - #xlsToPdf xlsToPdf.title=Excel para PDF xlsToPdf.header=Excel para PDF -xlsToPdf.selectText.1=Selecione planilha Excel XLS ou XLSX para converter -xlsToPdf.convert=converter - +xlsToPdf.selectText.1=Selecione a Planilha Excel XLS ou XLSX para Converter +xlsToPdf.convert=Converter #pdfToPDFA pdfToPDFA.title=PDF para PDF/A pdfToPDFA.header=PDF para PDF/A -pdfToPDFA.credit=Este serviço usa OCRmyPDF para conversão de PDF/A +pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A pdfToPDFA.submit=Converter - #PDFToWord PDFToWord.title=PDF para Word PDFToWord.header=PDF para Word -PDFToWord.selectText.1=Formato do arquivo de saída -PDFToWord.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToWord.selectText.1=Formato do Arquivo de Saída +PDFToWord.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToWord.submit=Converter - #PDFToPresentation -PDFToPresentation.title=PDF para apresentação -PDFToPresentation.header=PDF para apresentação -PDFToPresentation.selectText.1=Formato do arquivo de saída -PDFToPresentation.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToPresentation.title=PDF para Apresentação +PDFToPresentation.header=PDF para Apresentação +PDFToPresentation.selectText.1=Formato do Arquivo de Saída +PDFToPresentation.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToPresentation.submit=Converter - #PDFToText PDFToText.title=PDF para Texto/RTF PDFToText.header=PDF para Texto/RTF -PDFToText.selectText.1=Formato do arquivo de saída -PDFToText.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToText.selectText.1=Formato do Arquivo de Saída +PDFToText.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToText.submit=Converter - #PDFToHTML PDFToHTML.title=PDF para HTML PDFToHTML.header=PDF para HTML -PDFToHTML.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToHTML.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToHTML.submit=Converter - #PDFToXML PDFToXML.title=PDF para XML PDFToXML.header=PDF para XML -PDFToXML.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToXML.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToXML.submit=Converter From f9aa157c6c6b4e9fd269641c690ed0afa9b3cd22 Mon Sep 17 00:00:00 2001 From: adrielCarmoUFMS <141935947+adrielCarmoUFMS@users.noreply.github.com> Date: Thu, 10 Aug 2023 16:03:24 -0400 Subject: [PATCH 030/301] Update messages_pt_BR.properties Updating the translation of new features to the Portuguese - BR language --- src/main/resources/messages_pt_BR.properties | 771 +++++++++---------- 1 file changed, 357 insertions(+), 414 deletions(-) diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index e615c7304..7112ddf1a 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -26,11 +26,11 @@ text=Texto font=Fonte selectFillter=-- Selecione -- pageNum=Número de página -sizes.small=Small -sizes.medium=Medium -sizes.large=Large -sizes.x-large=X-Large -error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect +sizes.small=Pequeno +sizes.medium=Médio +sizes.large=Grande +sizes.x-large=Muito grande +error.pdfPassword=O documento PDF está protegido por senha e a senha não foi fornecida ou está incorreta ############# @@ -58,210 +58,199 @@ settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados e ############# # HOME-PAGE # ############# -home.desc=Seu melhor utilitário para as necessidades de PDF. - +home.desc=Seu melhor utilitário para suas necessidades de PDF. home.multiTool.title=Multiferramenta de PDF home.multiTool.desc=Mesclar, girar, reorganizar e remover páginas -multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side +multiTool.tags=Multi Ferramenta, Operação Múltipla, Interface do Usuário, Clique e Arraste, Front-end, Lado do Cliente -home.merge.title=mesclar -home.merge.desc=Mescle facilmente vários PDFs em um. -merge.tags=merge,Page operations,Back end,server side +home.merge.title=Mesclar +home.merge.desc=Mesclar facilmente vários PDFs em um só. +merge.tags=mesclar, Operações de Página, Lado do Servidor home.split.title=Dividir home.split.desc=Dividir PDFs em vários documentos -split.tags=Page operations,divide,Multi Page,cut,server side +split.tags=Operações de Página, dividir, Múltiplas Páginas, cortar, Lado do Servidor home.rotate.title=Girar -home.rotate.desc=Gire facilmente seus PDFs. -rotate.tags=server side - +home.rotate.desc=Girar facilmente seus PDFs. +rotate.tags=Lado do Servidor home.imageToPdf.title=Imagem para PDF -home.imageToPdf.desc=Converta uma imagem (PNG, JPEG, GIF) em PDF. -imageToPdf.tags=conversion,img,jpg,picture,photo +home.imageToPdf.desc=Converter uma imagem (PNG, JPEG, GIF) em PDF. +imageToPdf.tags=conversão, img, jpg, imagem, foto -home.pdfToImage.title=PDF para imagem -home.pdfToImage.desc=Converta um PDF em uma imagem. (PNG, JPG, GIF) -pdfToImage.tags=conversion,img,jpg,picture,photo +home.pdfToImage.title=PDF para Imagem +home.pdfToImage.desc=Converter um PDF em uma imagem. (PNG, JPG, GIF) +pdfToImage.tags=conversão, img, jpg, imagem, foto home.pdfOrganiser.title=Organizar -home.pdfOrganiser.desc=Remova/reorganize as páginas em qualquer ordem -pdfOrganiser.tags=duplex,even,odd,sort,move +home.pdfOrganiser.desc=Remover/reorganizar as páginas em qualquer ordem. +pdfOrganiser.tags=duplex, par, ímpar, ordenar, mover +home.addImage.title=Adicionar Imagem +home.addImage.desc=Adicionar uma imagem em um local definido no PDF (trabalho em andamento) +addImage.tags=img, jpg, imagem, foto -home.addImage.title=Adicionar imagem -home.addImage.desc=Adiciona uma imagem em um local definido no PDF (trabalho em andamento) -addImage.tags=img,jpg,picture,photo - -home.watermark.title=Adicione uma Marca d'água -home.watermark.desc=Adicione uma marca d'água personalizada ao seu documento PDF. -watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo - -home.permissions.title=Alterar permissões -home.permissions.desc=Altere as permissões do seu documento PDF -permissions.tags=read,write,edit,print +home.watermark.title=Adicionar Marca d'água +home.watermark.desc=Adicionar uma marca d'água personalizada ao seu documento PDF. +watermark.tags=Texto, repetindo, rótulo, próprio, direitos autorais, marca registrada, img, jpg, imagem, foto +home.permissions.title=Alterar Permissões +home.permissions.desc=Alterar as permissões do seu documento PDF. +permissions.tags=leitura, escrita, edição, impressão home.removePages.title=Remover -home.removePages.desc=Exclua as páginas indesejadas do seu documento PDF. -removePages.tags=Remove pages,delete pages +home.removePages.desc=Excluir as páginas indesejadas do seu documento PDF. +removePages.tags=Remover páginas, excluir páginas -home.addPassword.title=Adicionar senha -home.addPassword.desc=Criptografe seu documento PDF com uma senha. -addPassword.tags=secure,security +home.addPassword.title=Adicionar Senha +home.addPassword.desc=Criptografar seu documento PDF com uma senha. +addPassword.tags=seguro, segurança -home.removePassword.title=Remover senha -home.removePassword.desc=Remova a proteção por senha do seu documento PDF. -removePassword.tags=secure,Decrypt,security,unpassword,delete password +home.removePassword.title=Remover Senha +home.removePassword.desc=Remover a proteção por senha do seu documento PDF. +removePassword.tags=seguro, Descriptografar, segurança, remover senha home.compressPdfs.title=Comprimir -home.compressPdfs.desc=Comprima PDFs para reduzir o tamanho do arquivo. -compressPdfs.tags=squish,small,tiny +home.compressPdfs.desc=Comprimir PDFs para reduzir o tamanho do arquivo. +compressPdfs.tags=compactar, pequeno, mínimo +home.changeMetadata.title=Alterar Metadados +home.changeMetadata.desc=Alterar/remover/adicionar metadados de um documento PDF. +changeMetadata.tags=Título, autor, data, criação, hora, editor, produtor, estatísticas -home.changeMetadata.title=Alterar metadados -home.changeMetadata.desc=Alterar/remover/adicionar metadados de um documento PDF -changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats +home.fileToPDF.title=Converter Arquivo para PDF +home.fileToPDF.desc=Converter praticamente qualquer arquivo em PDF (DOCX, PNG, XLS, PPT, TXT e mais) +fileToPDF.tags=transformação, formato, documento, imagem, slide, texto, conversão, escritório, documentos, word, excel, powerpoint -home.fileToPDF.title=Converter arquivo para PDF -home.fileToPDF.desc=Converta praticamente qualquer arquivo em PDF (DOCX, PNG, XLS, PPT, TXT e mais) -fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint +home.ocr.title=OCR / Limpeza de Digitalizações +home.ocr.desc=A limpeza verifica e detecta texto em imagens de um PDF e o adiciona novamente como texto. +ocr.tags=reconhecimento, texto, imagem, digitalização, leitura, identificação, detecção, editável -home.ocr.title=OCR / Varreduras de limpeza -home.ocr.desc=A limpeza verifica e detecta texto de imagens em um PDF e o adiciona novamente como texto. -ocr.tags=recognition,text,image,scan,read,identify,detection,editable - - -home.extractImages.title=Extrair imagens -home.extractImages.desc=Extrai todas as imagens de um PDF e as salva em zip -extractImages.tags=picture,photo,save,archive,zip,capture,grab +home.extractImages.title=Extrair Imagens +home.extractImages.desc=Extrair todas as imagens de um PDF e salvá-las em um arquivo zip. +extractImages.tags=imagem, foto, salvar, arquivo, zip, captura, coleta home.pdfToPDFA.title=PDF para PDF/A -home.pdfToPDFA.desc=Converta PDF para PDF/A para armazenamento de longo prazo -pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation +home.pdfToPDFA.desc=Converter PDF para o formato PDF/A para armazenamento a longo prazo. +pdfToPDFA.tags=arquivo, longo prazo, padrão, conversão, armazenamento, preservação home.PDFToWord.title=PDF para Word home.PDFToWord.desc=Converter PDF para formatos Word (DOC, DOCX e ODT) -PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile +PDFToWord.tags=doc, docx, odt, word, transformação, formato, conversão, escritório, microsoft, arquivo doc -home.PDFToPresentation.title=PDF para apresentação +home.PDFToPresentation.title=PDF para Apresentação home.PDFToPresentation.desc=Converter PDF para formatos de apresentação (PPT, PPTX e ODP) -PDFToPresentation.tags=slides,show,office,microsoft +PDFToPresentation.tags=slides, apresentação, escritório, microsoft home.PDFToText.title=PDF para Texto/RTF home.PDFToText.desc=Converter PDF em formato de texto ou RTF -PDFToText.tags=richformat,richtextformat,rich text format +PDFToText.tags=formato rico, formato de texto enriquecido, formato de texto rico home.PDFToHTML.title=PDF para HTML home.PDFToHTML.desc=Converter PDF para o formato HTML -PDFToHTML.tags=web content,browser friendly - +PDFToHTML.tags=conteúdo web, compatível com navegador home.PDFToXML.title=PDF para XML home.PDFToXML.desc=Converter PDF para o formato XML -PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert +PDFToXML.tags=extração-de-dados,conteúdo-estruturado,interoperabilidade,transformação,converter -home.ScannerImageSplit.title=Detectar/dividir fotos digitalizadas -home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma foto/PDF -ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize +home.ScannerImageSplit.title=Detectar/Dividir Fotos Digitalizadas +home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma imagem/PDF digitalizado +ScannerImageSplit.tags=separar,detecção-automática,digitalizações,foto-múltipla,organizar -home.sign.title=Sinal -home.sign.desc=Adiciona assinatura ao PDF por desenho, texto ou imagem -sign.tags=authorize,initials,drawn-signature,text-sign,image-signature +home.sign.title=Assinar +home.sign.desc=Adicionar assinatura ao PDF por desenho, texto ou imagem +sign.tags=autorizar,iniciais,assinatura-desenhada,assinatura-de-texto,assinatura-de-imagem -home.flatten.title=achatar -home.flatten.desc=Remova todos os elementos e formulários interativos de um PDF -flatten.tags=static,deactivate,non-interactive,streamline +home.flatten.title=Achatar +home.flatten.desc=Remover todos os elementos e formulários interativos de um PDF +flatten.tags=estático,desativar,não-interativo,otimizar home.repair.title=Reparar -home.repair.desc=Tenta reparar um PDF corrompido/quebrado -repair.tags=fix,restore,correction,recover +home.repair.desc=Tentar reparar um PDF corrompido/quebrado +repair.tags=corrigir,restaurar,correção,recuperar -home.removeBlanks.title=Remover páginas em branco -home.removeBlanks.desc=Detecta e remove páginas em branco de um documento -removeBlanks.tags=cleanup,streamline,non-content,organize +home.removeBlanks.title=Remover Páginas em Branco +home.removeBlanks.desc=Detectar e remover páginas em branco de um documento +removeBlanks.tags=limpeza,otimização,sem-conteúdo,organizar home.compare.title=Comparar -home.compare.desc=Compara e mostra as diferenças entre 2 documentos PDF -compare.tags=differentiate,contrast,changes,analysis +home.compare.desc=Comparar e mostrar as diferenças entre 2 documentos PDF +compare.tags=diferenciar,contraste,mudanças,análise -home.certSign.title=Assinar com certificado -home.certSign.desc=Assina um PDF com um Certificado/Chave (PEM/P12) -certSign.tags=authenticate,PEM,P12,official,encrypt +home.certSign.title=Assinar com Certificado +home.certSign.desc=Assinar um PDF com um Certificado/Chave (PEM/P12) +certSign.tags=autenticar,PEM,P12,oficial,criptografar -home.pageLayout.title=Multi-Page Layout -home.pageLayout.desc=Merge multiple pages of a PDF document into a single page -pageLayout.tags=merge,composite,single-view,organize +home.pageLayout.title=Layout de Múltiplas Páginas +home.pageLayout.desc=Mesclar várias páginas de um documento PDF em uma única página +pageLayout.tags=mesclar,composto,vista-única,organizar -home.scalePages.title=Adjust page size/scale -home.scalePages.desc=Change the size/scale of page and/or its contents. -scalePages.tags=resize,modify,dimension,adapt +home.scalePages.title=Ajustar Tamanho/Escala de Página +home.scalePages.desc=Alterar o tamanho/escala da página e/ou seu conteúdo. +scalePages.tags=redimensionar,modificar,dimensão,adaptar -home.pipeline.title=Pipeline (Advanced) -home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts -pipeline.tags=automate,sequence,scripted,batch-process +home.pipeline.title=Pipeline (Avançado) +home.pipeline.desc=Executar várias ações em PDFs definindo scripts de pipeline +pipeline.tags=automatizar,sequência,scriptado,processo-em-lote -home.add-page-numbers.title=Add Page Numbers -home.add-page-numbers.desc=Add Page numbers throughout a document in a set location -add-page-numbers.tags=paginate,label,organize,index +home.add-page-numbers.title=Adicionar Números de Página +home.add-page-numbers.desc=Adicionar números de página em todo o documento em um local definido +add-page-numbers.tags=paginar,rotular,organizar,índice -home.auto-rename.title=Auto Rename PDF File -home.auto-rename.desc=Auto renames a PDF file based on its detected header -auto-rename.tags=auto-detect,header-based,organize,relabel +home.auto-rename.title=Renomear Automaticamente o Arquivo PDF +home.auto-rename.desc=Renomeia automaticamente um arquivo PDF com base no cabeçalho detectado +auto-rename.tags=detecção-automática,baseado-em-cabeçalho,organizar,relabel -home.adjust-contrast.title=Adjust Colors/Contrast -home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF -adjust-contrast.tags=color-correction,tune,modify,enhance +home.adjust-contrast.title=Ajustar Cores/Contraste +home.adjust-contrast.desc=Ajustar Contraste, Saturação e Brilho de um PDF +adjust-contrast.tags=correção-de-cor,ajustar,modificar,realçar -home.crop.title=Crop PDF -home.crop.desc=Crop a PDF to reduce its size (maintains text!) -crop.tags=trim,shrink,edit,shape +home.crop.title=Cortar PDF +home.crop.desc=Cortar um PDF para reduzir o tamanho (mantém o texto!) +crop.tags=aparar,encolher,editar,formato -home.autoSplitPDF.title=Auto Split Pages -home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code -autoSplitPDF.tags=QR-based,separate,scan-segment,organize +home.autoSplitPDF.title=Divisão Automática de Páginas +home.autoSplitPDF.desc=Dividir automaticamente um PDF digitalizado com separador de páginas físicas QR Code +autoSplitPDF.tags=baseado-em-QR,separar,segmento-de-digitalização,organizar -home.sanitizePdf.title=Sanitize -home.sanitizePdf.desc=Remove scripts and other elements from PDF files -sanitizePdf.tags=clean,secure,safe,remove-threats +home.sanitizePdf.title=Sanitizar +home.sanitizePdf.desc=Remover scripts e outros elementos de arquivos PDF +sanitizePdf.tags=limpar,seguro,protegido,remover-ameaças -home.URLToPDF.title=URL/Website To PDF -home.URLToPDF.desc=Converts any http(s)URL to PDF -URLToPDF.tags=web-capture,save-page,web-to-doc,archive +home.URLToPDF.title=URL/Site para PDF +home.URLToPDF.desc=Converte qualquer URL http(s) para PDF +URLToPDF.tags=captura-de-web,salvar-página,web-para-doc,arquivar -home.HTMLToPDF.title=HTML to PDF -home.HTMLToPDF.desc=Converts any HTML file or zip to PDF -HTMLToPDF.tags=markup,web-content,transformation,convert +home.HTMLToPDF.title=HTML para PDF +home.HTMLToPDF.desc=Converte qualquer arquivo HTML ou zip para PDF +HTMLToPDF.tags=marcação,conteúdo-web,transformação,converter +home.MarkdownToPDF.title=Markdown para PDF +home.MarkdownToPDF.desc=Converte qualquer arquivo Markdown para PDF +MarkdownToPDF.tags=marcação,conteúdo-web,transformação,converter -home.MarkdownToPDF.title=Markdown to PDF -home.MarkdownToPDF.desc=Converts any Markdown file to PDF -MarkdownToPDF.tags=markup,web-content,transformation,convert +home.getPdfInfo.title=Obter TODAS as Informações de um PDF +home.getPdfInfo.desc=Obtém todas as informações possíveis de um PDF +getPdfInfo.tags=informações,dados,estatísticas +home.extractPage.title=Extrair Página(s) +home.extractPage.desc=Extrai páginas selecionadas de um PDF +extractPage.tags=extrair -home.getPdfInfo.title=Get ALL Info on PDF -home.getPdfInfo.desc=Grabs any and all information possible on PDFs -getPdfInfo.tags=infomation,data,stats,statistics - - -home.extractPage.title=Extract page(s) -home.extractPage.desc=Extracts select pages from PDF -extractPage.tags=extract - - -home.PdfToSinglePage.title=PDF to Single Large Page -home.PdfToSinglePage.desc=Merges all PDF pages into one large single page -PdfToSinglePage.tags=single page +home.PdfToSinglePage.title=PDF para Página Única Grande +home.PdfToSinglePage.desc=Combina todas as páginas de um PDF em uma única página grande +PdfToSinglePage.tags=página única ########################## ### TODO: Translate ### ########################## -home.showJS.title=Show Javascript -home.showJS.desc=Searches and displays any JS injected into a PDF -showJS.tags=JS +home.showJS.title=Mostrar Javascript +home.showJS.desc=Procura e exibe qualquer JavaScript injetado em um PDF +showJS.tags=JavaScript ########################### # # @@ -272,158 +261,140 @@ showJS.tags=JS ########################## ### TODO: Translate ### ########################## -showJS.title=Show Javascript -showJS.header=Show Javascript -showJS.downloadJS=Download Javascript -showJS.submit=Show - +showJS.title=Exibir JavaScript +showJS.header=Exibir JavaScript +showJS.downloadJS=Download do JavaScript +showJS.submit=Exibir #pdfToSinglePage -pdfToSinglePage.title=PDF To Single Page -pdfToSinglePage.header=PDF To Single Page -pdfToSinglePage.submit=Convert To Single Page - +pdfToSinglePage.title=PDF para Página Única +pdfToSinglePage.header=PDF para Página Única +pdfToSinglePage.submit=Converter para Página Única #pageExtracter -pageExtracter.title=Extract Pages -pageExtracter.header=Extract Pages -pageExtracter.submit=Extract - +pageExtracter.title=Extrair Páginas +pageExtracter.header=Extrair Páginas +pageExtracter.submit=Extrair #getPdfInfo -getPdfInfo.title=Get Info on PDF -getPdfInfo.header=Get Info on PDF -getPdfInfo.submit=Get Info +getPdfInfo.title=Obter Informações do PDF +getPdfInfo.header=Obter Informações do PDF +getPdfInfo.submit=Obter Informações getPdfInfo.downloadJson=Download JSON - #markdown-to-pdf -MarkdownToPDF.title=Markdown To PDF -MarkdownToPDF.header=Markdown To PDF -MarkdownToPDF.submit=Convert -MarkdownToPDF.help=Work in progress -MarkdownToPDF.credit=Uses WeasyPrint - - +MarkdownToPDF.title=Markdown para PDF +MarkdownToPDF.header=Markdown para PDF +MarkdownToPDF.submit=Converter +MarkdownToPDF.help=Trabalho em andamento +MarkdownToPDF.credit=Usa o WeasyPrint #url-to-pdf -URLToPDF.title=URL To PDF -URLToPDF.header=URL To PDF -URLToPDF.submit=Convert -URLToPDF.credit=Uses WeasyPrint - +URLToPDF.title=URL para PDF +URLToPDF.header=URL para PDF +URLToPDF.submit=Converter +URLToPDF.credit=Usa o WeasyPrint #html-to-pdf -HTMLToPDF.title=HTML To PDF -HTMLToPDF.header=HTML To PDF -HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required -HTMLToPDF.submit=Convert -HTMLToPDF.credit=Uses WeasyPrint - +HTMLToPDF.title=HTML para PDF +HTMLToPDF.header=HTML para PDF +HTMLToPDF.help=Aceita arquivos HTML e ZIPs contendo html/css/imagens etc necessários +HTMLToPDF.submit=Converter +HTMLToPDF.credit=Usa o WeasyPrint #sanitizePDF -sanitizePDF.title=Sanitize PDF -sanitizePDF.header=Sanitize a PDF file -sanitizePDF.selectText.1=Remove JavaScript actions -sanitizePDF.selectText.2=Remove embedded files -sanitizePDF.selectText.3=Remove metadata -sanitizePDF.selectText.4=Remove links -sanitizePDF.selectText.5=Remove fonts -sanitizePDF.submit=Sanitize PDF - +sanitizePDF.title=Sanitizar PDF +sanitizePDF.header=Sanitizar um arquivo PDF +sanitizePDF.selectText.1=Remover ações de JavaScript +sanitizePDF.selectText.2=Remover arquivos embutidos +sanitizePDF.selectText.3=Remover metadados +sanitizePDF.selectText.4=Remover links +sanitizePDF.selectText.5=Remover fontes +sanitizePDF.submit=Sanitizar PDF #addPageNumbers -addPageNumbers.title=Add Page Numbers -addPageNumbers.header=Add Page Numbers -addPageNumbers.selectText.1=Select PDF file: -addPageNumbers.selectText.2=Margin Size -addPageNumbers.selectText.3=Position -addPageNumbers.selectText.4=Starting Number -addPageNumbers.selectText.5=Pages to Number -addPageNumbers.selectText.6=Custom Text -addPageNumbers.submit=Add Page Numbers - +addPageNumbers.title=Adicionar Números de Página +addPageNumbers.header=Adicionar Números de Página +addPageNumbers.selectText.1=Selecionar arquivo PDF: +addPageNumbers.selectText.2=Tamanho da Margem +addPageNumbers.selectText.3=Posição +addPageNumbers.selectText.4=Número Inicial +addPageNumbers.selectText.5=Páginas a Numerar +addPageNumbers.selectText.6=Texto Personalizado +addPageNumbers.submit=Adicionar Números de Página #auto-rename -auto-rename.title=Auto Rename -auto-rename.header=Auto Rename PDF -auto-rename.submit=Auto Rename - +auto-rename.title=Rename Automático +auto-rename.header=Rename Automático de PDF +auto-rename.submit=Rename Automático #adjustContrast -adjustContrast.title=Adjust Contrast -adjustContrast.header=Adjust Contrast -adjustContrast.contrast=Contrast: -adjustContrast.brightness=Brightness: -adjustContrast.saturation=Saturation: +adjustContrast.title=Ajustar Contraste +adjustContrast.header=Ajustar Contraste +adjustContrast.contrast=Contraste: +adjustContrast.brightness=Brilho: +adjustContrast.saturation=Saturação: adjustContrast.download=Download - #crop -crop.title=Crop -crop.header=Crop Image -crop.submit=Submit - +crop.title=Cortar +crop.header=Cortar Imagem +crop.submit=Enviar #autoSplitPDF -autoSplitPDF.title=Auto Split PDF -autoSplitPDF.header=Auto Split PDF -autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed. -autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine). -autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them. -autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest. -autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document. -autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers: -autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning) -autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf' -autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf' -autoSplitPDF.submit=Submit - +autoSplitPDF.title=Divisão Automática de PDF +autoSplitPDF.header=Divisão Automática de PDF +autoSplitPDF.description=Imprima, insira, digitalize, faça o upload e deixe que a gente divida seus documentos automaticamente. Nenhuma classificação manual necessária. +autoSplitPDF.selectText.1=Imprima algumas folhas divisórias abaixo (preto e branco está bom). +autoSplitPDF.selectText.2=Digitalize todos os seus documentos de uma vez, inserindo a folha divisória entre eles. +autoSplitPDF.selectText.3=Faça o upload do único arquivo PDF grande digitalizado e deixe o Stirling PDF cuidar do resto. +autoSplitPDF.selectText.4=As páginas divisórias são detectadas e removidas automaticamente, garantindo um documento final organizado. +autoSplitPDF.formPrompt=Enviar PDF contendo folhas divisórias Stirling-PDF: +autoSplitPDF.duplexMode=Modo Duplex (Digitalização frente e verso) +autoSplitPDF.dividerDownload1=Download 'Folha Divisória Automática (mínima).pdf' +autoSplitPDF.dividerDownload2=Download 'Folha Divisória Automática (com instruções).pdf' +autoSplitPDF.submit=Enviar #pipeline pipeline.title=Pipeline #pageLayout -pageLayout.title=Multi Page Layout -pageLayout.header=Multi Page Layout -pageLayout.pagesPerSheet=Pages per sheet: -pageLayout.submit=Submit - +pageLayout.title=Layout de Múltiplas Páginas +pageLayout.header=Layout de Múltiplas Páginas +pageLayout.pagesPerSheet=Páginas por folha: +pageLayout.submit=Enviar #scalePages -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 - +scalePages.title=Ajustar Tamanho/Escala da Página +scalePages.header=Ajustar Tamanho/Escala da Página +scalePages.pageSize=Tamanho de uma página do documento. +scalePages.scaleFactor=Fator de zoom (corte) de uma página. +scalePages.submit=Enviar #certSign -certSign.title=Assinatura de certificado -certSign.header=Assine um PDF com seu certificado (Trabalho em andamento) +certSign.title=Assinatura com Certificado +certSign.header=Assine um PDF com o seu certificado (Em desenvolvimento) certSign.selectPDF=Selecione um arquivo PDF para assinatura: -certSign.selectKey=Selecione seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der): -certSign.selectCert=Selecione seu arquivo de certificado (formato X.509, pode ser .pem ou .der): -certSign.selectP12=Selecione seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter sua chave privada e certificado): -certSign.certType=tipo de certificado -certSign.password=Digite seu armazenamento de chave ou senha de chave privada (se houver): -certSign.showSig=Mostrar assinatura +certSign.selectKey=Selecione o seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der): +certSign.selectCert=Selecione o seu arquivo de certificado (formato X.509, pode ser .pem ou .der): +certSign.selectP12=Selecione o seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter a sua chave privada e certificado): +certSign.certType=Tipo de Certificado +certSign.password=Digite a senha do seu armazenamento de chave ou chave privada (se aplicável): +certSign.showSig=Mostrar Assinatura certSign.reason=Razão certSign.location=Localização certSign.name=Nome certSign.submit=Assinar PDF - #removeBlanks -removeBlanks.title=Remover espaços em branco -removeBlanks.header=Remover páginas em branco -removeBlanks.threshold=Limite: -removeBlanks.thresholdDesc=Limiar para determinar quão branco um pixel branco deve ser -removeBlanks.whitePercent=Porcentagem branca (%): +removeBlanks.title=Remover Páginas em Branco +removeBlanks.header=Remover Páginas em Branco +removeBlanks.threshold=Limiar: +removeBlanks.thresholdDesc=Limiar para determinar o quão branco um pixel branco deve ser +removeBlanks.whitePercent=Porcentagem de Branco (%): removeBlanks.whitePercentDesc=Porcentagem da página que deve ser branca para ser removida -removeBlanks.submit=Remover espaços em branco - +removeBlanks.submit=Remover Páginas em Branco #compare compare.title=Comparar @@ -432,28 +403,24 @@ compare.document.1=Documento 1 compare.document.2=Documento 2 compare.submit=Comparar - #sign -sign.title=Sinal +sign.title=Assinar sign.header=Assinar PDFs sign.upload=Enviar Imagem sign.draw=Desenhar Assinatura -sign.text=Entrada de texto -sign.clear=Claro +sign.text=Inserir Texto +sign.clear=Limpar sign.add=Adicionar - #repair repair.title=Reparar repair.header=Reparar PDFs repair.submit=Reparar - #flatten -flatten.title=achatar +flatten.title=Achatar flatten.header=Achatar PDFs -flatten.submit=achatar - +flatten.submit=Achatar #ScannerImageSplit ScannerImageSplit.selectText.1=Limite de Ângulo: @@ -469,266 +436,242 @@ ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida #OCR -ocr.title=OCR / Limpeza de digitalização -ocr.header=Varreduras de limpeza / OCR (reconhecimento óptico de caracteres) -ocr.selectText.1=Selecione os idiomas que devem ser detectados no PDF (os listados são os atualmente detectados): -ocr.selectText.2=Produzir arquivo de texto contendo texto OCR ao lado do PDF com OCR -ocr.selectText.3=As páginas corretas foram digitalizadas em um ângulo inclinado girando-as de volta ao lugar -ocr.selectText.4=Limpe a página para que seja menos provável que o OCR encontre o texto no ruído de fundo. (Sem mudança de saída) -ocr.selectText.5=Limpe a página para que seja menos provável que o OCR encontre texto no ruído de fundo, mantendo a limpeza na saída. -ocr.selectText.6=Ignora as páginas que contêm texto interativo, apenas as páginas de OCR que são imagens -ocr.selectText.7=Forçar OCR, irá OCR Todas as páginas removendo todos os elementos de texto originais -ocr.selectText.8=Normal (será um erro se o PDF contiver texto) +ocr.title=OCR / Limpeza de Digitalização +ocr.header=OCR / Limpeza de Digitalização (Reconhecimento Óptico de Caracteres) +ocr.selectText.1=Selecione os idiomas a serem detectados no PDF (os listados são os atualmente detectados): +ocr.selectText.2=Criar um arquivo de texto contendo o texto OCR ao lado do PDF com OCR +ocr.selectText.3=Páginas corretamente digitalizadas em um ângulo inclinado, gire-as de volta à posição original +ocr.selectText.4=Limpar a página para reduzir a probabilidade de o OCR encontrar texto no ruído de fundo (sem alteração na saída) +ocr.selectText.5=Limpar a página para reduzir a probabilidade de o OCR encontrar texto no ruído de fundo, mantendo a limpeza na saída. +ocr.selectText.6=Ignorar páginas com texto interativo, processar apenas as páginas de OCR que são imagens +ocr.selectText.7=Forçar OCR, executar OCR em todas as páginas, removendo todos os elementos de texto originais +ocr.selectText.8=Normal (gerará um erro se o PDF já contiver texto) ocr.selectText.9=Configurações adicionais ocr.selectText.10=Modo OCR -ocr.selectText.11=Remova as imagens após o OCR (remove TODAS as imagens, útil apenas se fizer parte da etapa de conversão) -ocr.selectText.12=Tipo de renderização (avançado) -ocr.help=Por favor, leia esta documentação sobre como usar isso para outros idiomas e/ou não usar no docker +ocr.selectText.11=Remover imagens após o OCR (remove TODAS as imagens, útil apenas como parte do processo de conversão) +ocr.help=Por favor, leia a documentação sobre como usar isso para outros idiomas e/ou fora do ambiente Docker ocr.credit=Este serviço usa OCRmyPDF e Tesseract para OCR. ocr.submit=Processar PDF com OCR - #extractImages extractImages.title=Extrair Imagens extractImages.header=Extrair Imagens -extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas em +extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas extractImages.submit=Extrair - #File to PDF fileToPDF.title=Arquivo para PDF -fileToPDF.header=Converta qualquer arquivo para PDF -fileToPDF.credit=Este serviço usa LibreOffice e Unoconv para conversão de arquivos. -fileToPDF.supportedFileTypes=Os tipos de arquivo suportados devem incluir o abaixo, no entanto, para obter uma lista atualizada completa de formatos suportados, consulte a documentação do LibreOffice +fileToPDF.header=Converter Qualquer Arquivo para PDF +fileToPDF.credit=Este serviço usa o LibreOffice e o Unoconv para conversão de arquivos. +fileToPDF.supportedFileTypes=Os tipos de arquivo suportados devem incluir os listados abaixo. No entanto, para obter uma lista atualizada completa dos formatos suportados, consulte a documentação do LibreOffice. fileToPDF.submit=Converter para PDF - #compress compress.title=Comprimir compress.header=Comprimir PDF compress.credit=Este serviço usa o Ghostscript para compressão/otimização de PDF. compress.selectText.1=Modo Manual - De 1 a 4 -compress.selectText.2=Nível de otimização: -compress.selectText.3=4 (Péssimo para imagens de texto) -compress.selectText.4=Modo automático - Auto ajusta a qualidade para obter o tamanho exato do PDF -compress.selectText.5=Tamanho esperado do PDF (por exemplo, 25 MB, 10,8 MB, 25 KB) +compress.selectText.2=Nível de Otimização: +compress.selectText.3=4 (Pior para imagens de texto) +compress.selectText.4=Modo Automático - Ajusta automaticamente a qualidade para atingir o tamanho exato do PDF +compress.selectText.5=Tamanho Esperado do PDF (por exemplo, 25 MB, 10,8 MB, 25 KB) compress.submit=Comprimir - #Add image -addImage.title=Adicionar imagem -addImage.header=Adicionar imagem ao PDF -addImage.everyPage=Cada página? -addImage.upload=Adicionar imagem -addImage.submit=Adicionar imagem - +addImage.title=Adicionar Imagem +addImage.header=Adicionar Imagem ao PDF +addImage.everyPage=Para cada página? +addImage.upload=Enviar Imagem +addImage.submit=Adicionar Imagem #merge -merge.title=mesclar -merge.header=Mesclar vários PDFs (2+) -merge.submit=mesclar - +merge.title=Mesclar +merge.header=Mesclar Vários PDFs (2+) +merge.submit=Mesclar #pdfOrganiser -pdfOrganiser.title=Organizador de página -pdfOrganiser.header=Organizador de páginas PDF -pdfOrganiser.submit=Reorganizar páginas - +pdfOrganiser.title=Organizador de Páginas +pdfOrganiser.header=Organizador de Páginas PDF +pdfOrganiser.submit=Reorganizar Páginas #multiTool multiTool.title=Multiferramenta de PDF multiTool.header=Multiferramenta de PDF - #pageRemover -pageRemover.title=Removedor de página -pageRemover.header=Removedor de página PDF -pageRemover.pagesToDelete=Páginas a serem excluídas (digite uma lista separada por vírgulas de números de página): -pageRemover.submit=Excluir páginas - +pageRemover.title=Remover Página +pageRemover.header=Remover Páginas do PDF +pageRemover.pagesToDelete=Páginas a serem excluídas (insira uma lista separada por vírgulas de números de página): +pageRemover.submit=Excluir Páginas #rotate rotate.title=Girar PDF rotate.header=Girar PDF -rotate.selectAngle=Selecione o ângulo de rotação (em múltiplos de 90 graus): +rotate.selectAngle=Selecione o ângulo de rotação (múltiplos de 90 graus): rotate.submit=Girar - #merge -split.title=PDF dividido -split.header=PDF dividido -split.desc.1=Os números que você selecionar são o número da página na qual você deseja fazer uma divisão -split.desc.2=Assim, selecionar 1,3,7-8 dividiria um documento de 10 páginas em 6 PDFS separados com: -split.desc.3=Documento nº 1: página 1 -split.desc.4=Documento nº 2: páginas 2 e 3 -split.desc.5=Documento nº 3: Página 4, 5 e 6 -split.desc.6=Documento nº 4: página 7 -split.desc.7=Documento nº 5: página 8 -split.desc.8=Documento nº 6: páginas 9 e 10 -split.splitPages=Digite as páginas para dividir: +split.title=Dividir PDF +split.header=Dividir PDF +split.desc.1=Os números selecionados correspondem às páginas onde você deseja fazer a divisão. +split.desc.2,3,4,5,6,7,8=Por exemplo, selecionar 1,3,7-8 dividirá um documento de 10 páginas em 6 PDFs separados da seguinte forma: +split.desc.2=Documento 1: Página 1 +split.desc.3=Documento 2: Páginas 2 e 3 +split.desc.4=Documento 3: Páginas 4, 5 e 6 +split.desc.5=Documento 4: Página 7 +split.desc.6=Documento 5: Página 8 +split.desc.7=Documento 6: Páginas 9 e 10 +split.splitPages=Digite as páginas para a divisão: split.submit=Dividir - #merge imageToPDF.title=Imagem para PDF -imageToPDF.header=Imagem para PDF +imageToPDF.header=Converter Imagem para PDF imageToPDF.submit=Converter -imageToPDF.selectText.1=Esticar para caber -imageToPDF.selectText.2=Girar PDF automaticamente -imageToPDF.selectText.3=Lógica de vários arquivos (Ativado apenas se estiver trabalhando com várias imagens) -imageToPDF.selectText.4=Mesclar em um único PDF -imageToPDF.selectText.5=Converter em PDFs separados - - +imageToPDF.selectText.1=Esticar para Ajustar +imageToPDF.selectText.2=Girar Automaticamente +imageToPDF.selectText.3=Lógica de Vários Arquivos (Ativada apenas ao trabalhar com várias imagens) +imageToPDF.selectText.4=Mesclar em um Único PDF +imageToPDF.selectText.5=Converter em PDFs Separados + #pdfToImage -pdfToImage.title=PDF para imagem -pdfToImage.header=PDF para imagem -pdfToImage.selectText=Formato de imagem -pdfToImage.singleOrMultiple=Tipo de resultado de imagem -pdfToImage.single=Imagem grande única -pdfToImage.multi=Imagens múltiplas -pdfToImage.colorType=tipo de cor -pdfToImage.color=Cor -pdfToImage.grey=Escala de cinza -pdfToImage.blackwhite=Preto e branco (pode perder dados!) +pdfToImage.title=PDF para Imagem +pdfToImage.header=Converter PDF para Imagem +pdfToImage.selectText=Formato de Imagem +pdfToImage.singleOrMultiple=Tipo de Resultado de Imagem +pdfToImage.single=Única Imagem Grande +pdfToImage.multi=Múltiplas Imagens +pdfToImage.colorType=Tipo de Cor +pdfToImage.color=Colorida +pdfToImage.grey=Escala de Cinza +pdfToImage.blackwhite=Preto e Branco (pode resultar em perda de dados!) pdfToImage.submit=Converter #addPassword -addPassword.title=Adicionar senha -addPassword.header=Adicionar senha (Criptografar) -addPassword.selectText.1=Selecione PDF para criptografar +addPassword.title=Adicionar Senha +addPassword.header=Adicionar Senha (Criptografar) +addPassword.selectText.1=Selecione o PDF para Criptografar addPassword.selectText.2=Senha -addPassword.selectText.3=Comprimento da chave de criptografia -addPassword.selectText.4=Valores mais altos são mais fortes, mas valores mais baixos têm melhor compatibilidade. -addPassword.selectText.5=Permissões para definir -addPassword.selectText.6=Impedir a montagem do documento -addPassword.selectText.7=Impedir a extração de conteúdo -addPassword.selectText.8=Impedir a extração para acessibilidade -addPassword.selectText.9=Impedir o preenchimento do formulário -addPassword.selectText.10=Impedir modificação -addPassword.selectText.11=Impedir a modificação da anotação -addPassword.selectText.12=Impedir a impressão -addPassword.selectText.13=Impedir a impressão de formatos diferentes -addPassword.selectText.14=Owner Password -addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers) -addPassword.selectText.16=Restricts the opening of the document itself -addPassword.submit=criptografar - +addPassword.selectText.3=Tamanho da Chave de Criptografia +addPassword.selectText.4=Valores mais altos são mais seguros, mas valores mais baixos são mais compatíveis. +addPassword.selectText.5=Permissões para Definir +addPassword.selectText.6=Impedir Montagem do Documento +addPassword.selectText.7=Impedir Extração de Conteúdo +addPassword.selectText.8=Impedir Extração para Acessibilidade +addPassword.selectText.9=Impedir Preenchimento de Formulário +addPassword.selectText.10=Impedir Modificação +addPassword.selectText.11=Impedir Modificação de Anotação +addPassword.selectText.12=Impedir Impressão +addPassword.selectText.13=Impedir Impressão de Formatos Diferentes +addPassword.selectText.14=Senha do Proprietário +addPassword.selectText.15=Restringe o que pode ser feito com o documento após a abertura (nem todos os leitores dão suporte a isso) +addPassword.selectText.16=Restringe a abertura do próprio documento +addPassword.submit=Criptografar #watermark -watermark.title=Adicione uma Marca d'água -watermark.header=Adicione uma Marca d'água -watermark.selectText.1=Selecione PDF para adicionar marca d'água a: -watermark.selectText.2=Texto da marca d'água: -watermark.selectText.3=Tamanho da fonte: -watermark.selectText.4=Rotação (0-360): -watermark.selectText.5=widthSpacer (espaço entre cada marca d'água horizontalmente): -watermark.selectText.6=heightSpacer (espaço entre cada marca d'água verticalmente): -watermark.selectText.7=Opacidade (0% - 100%): -watermark.submit=Adicione uma Marca d'água - +watermark.title=Adicionar Marca d'Água +watermark.header=Adicionar Marca d'Água +watermark.selectText.1=Selecione o PDF para Adicionar a Marca d'Água +watermark.selectText.2=Texto da Marca d'Água +watermark.selectText.3=Tamanho da Fonte +watermark.selectText.4=Rotação (0-360) +watermark.selectText.5=Espaçamento Horizontal (widthSpacer) +watermark.selectText.6=Espaçamento Vertical (heightSpacer) +watermark.selectText.7=Opacidade (0% - 100%) +watermark.submit=Adicionar Marca d'Água #remove-watermark -remove-watermark.title=Remover marca d'água -remove-watermark.header=Remover marca d'água -remove-watermark.selectText.1=Selecione PDF para remover a marca d'água de: -remove-watermark.selectText.2=Texto da marca d'água: -remove-watermark.submit=Remover marca d'água - +remove-watermark.title=Remover Marca d'Água +remove-watermark.header=Remover Marca d'Água +remove-watermark.selectText.1=Selecione o PDF para Remover a Marca d'Água +remove-watermark.selectText.2=Texto da Marca d'Água +remove-watermark.submit=Remover Marca d'Água #Change permissions -permissions.title=Alterar permissões -permissions.header=Alterar permissões -permissions.warning=Aviso para que essas permissões sejam inalteráveis, é recomendável defini-las com uma senha por meio da página adicionar senha -permissions.selectText.1=Selecione o PDF para alterar as permissões -permissions.selectText.2=Permissões para definir -permissions.selectText.3=Impedir a montagem do documento -permissions.selectText.4=Impedir a extração de conteúdo -permissions.selectText.5=Impedir extração para acessibilidade -permissions.selectText.6=Impedir o preenchimento do formulário -permissions.selectText.7=Impedir modificações -permissions.selectText.8=Impedir a modificação da anotação -permissions.selectText.9=Impedir a impressão -permissions.selectText.10=Impedir a impressão de formatos diferentes +permissions.title=Alterar Permissões +permissions.header=Alterar Permissões +permissions.warning=Nota: Para tornar essas permissões inalteráveis, é recomendável defini-las com uma senha através da página "Adicionar Senha". +permissions.selectText.1=Selecione o PDF para Alterar as Permissões +permissions.selectText.2=Permissões para Definir +permissions.selectText.3=Impedir Montagem do Documento +permissions.selectText.4=Impedir Extração de Conteúdo +permissions.selectText.5=Impedir Extração para Acessibilidade +permissions.selectText.6=Impedir Preenchimento de Formulário +permissions.selectText.7=Impedir Modificações +permissions.selectText.8=Impedir Modificação de Anotação +permissions.selectText.9=Impedir Impressão +permissions.selectText.10=Impedir Impressão de Formatos Diferentes permissions.submit=Mudar - #remove password -removePassword.title=Remover senha -removePassword.header=Remover senha (Descriptografar) -removePassword.selectText.1=Selecione PDF para descriptografar +removePassword.title=Remover Senha +removePassword.header=Remover Senha (Descriptografar) +removePassword.selectText.1=Selecione o PDF para Descriptografar removePassword.selectText.2=Senha removePassword.submit=Remover #changeMetadata -changeMetadata.title=Título: -changeMetadata.header=Alterar metadados -changeMetadata.selectText.1=Edite as variáveis que deseja alterar -changeMetadata.selectText.2=Excluir todos os metadados -changeMetadata.selectText.3=Mostrar metadados personalizados: +changeMetadata.title=Alterar Metadados +changeMetadata.header=Alterar Metadados +changeMetadata.selectText.1=Edite as Variáveis que Deseja Alterar +changeMetadata.selectText.2=Excluir Todos os Metadados +changeMetadata.selectText.3=Mostrar Metadados Personalizados changeMetadata.author=Autor: changeMetadata.creationDate=Data de Criação (aaaa/MM/dd HH:mm:ss): -changeMetadata.creator=O Criador: +changeMetadata.creator=Criador: changeMetadata.keywords=Palavras-chave: -changeMetadata.modDate=Data de modificação (aaaa/MM/dd HH:mm:ss): +changeMetadata.modDate=Data de Modificação (aaaa/MM/dd HH:mm:ss): changeMetadata.producer=Produtor: changeMetadata.subject=Assunto: changeMetadata.title=Título: -changeMetadata.trapped=Encurralado: -changeMetadata.selectText.4=Outros metadados: -changeMetadata.selectText.5=Adicionar entrada de metadados personalizados +changeMetadata.trapped=Trapped: +changeMetadata.selectText.4=Outros Metadados +changeMetadata.selectText.5=Adicionar Entrada de Metadados Personalizados changeMetadata.submit=Mudar - #xlsToPdf xlsToPdf.title=Excel para PDF xlsToPdf.header=Excel para PDF -xlsToPdf.selectText.1=Selecione planilha Excel XLS ou XLSX para converter -xlsToPdf.convert=converter - +xlsToPdf.selectText.1=Selecione a Planilha Excel XLS ou XLSX para Converter +xlsToPdf.convert=Converter #pdfToPDFA pdfToPDFA.title=PDF para PDF/A pdfToPDFA.header=PDF para PDF/A -pdfToPDFA.credit=Este serviço usa OCRmyPDF para conversão de PDF/A +pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A pdfToPDFA.submit=Converter - #PDFToWord PDFToWord.title=PDF para Word PDFToWord.header=PDF para Word -PDFToWord.selectText.1=Formato do arquivo de saída -PDFToWord.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToWord.selectText.1=Formato do Arquivo de Saída +PDFToWord.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToWord.submit=Converter - #PDFToPresentation -PDFToPresentation.title=PDF para apresentação -PDFToPresentation.header=PDF para apresentação -PDFToPresentation.selectText.1=Formato do arquivo de saída -PDFToPresentation.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToPresentation.title=PDF para Apresentação +PDFToPresentation.header=PDF para Apresentação +PDFToPresentation.selectText.1=Formato do Arquivo de Saída +PDFToPresentation.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToPresentation.submit=Converter - #PDFToText PDFToText.title=PDF para Texto/RTF PDFToText.header=PDF para Texto/RTF -PDFToText.selectText.1=Formato do arquivo de saída -PDFToText.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToText.selectText.1=Formato do Arquivo de Saída +PDFToText.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToText.submit=Converter - #PDFToHTML PDFToHTML.title=PDF para HTML PDFToHTML.header=PDF para HTML -PDFToHTML.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToHTML.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToHTML.submit=Converter - #PDFToXML PDFToXML.title=PDF para XML PDFToXML.header=PDF para XML -PDFToXML.credit=Este serviço usa o LibreOffice para conversão de arquivos. +PDFToXML.credit=Este serviço usa o LibreOffice para Conversão de Arquivos. PDFToXML.submit=Converter From 232a305d51393f7375582a06a0fbebcd0c9659f7 Mon Sep 17 00:00:00 2001 From: Jacob Braun Date: Thu, 10 Aug 2023 13:27:56 -0700 Subject: [PATCH 031/301] Add additional spelling changes for US translations Add additional spelling changes for US translations --- src/main/resources/messages_en_US.properties | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 8f9ac8487..b1b05e24f 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -524,8 +524,8 @@ merge.submit=Merge #pdfOrganiser -pdfOrganiser.title=Page Organiser -pdfOrganiser.header=PDF Page Organiser +pdfOrganiser.title=Page Organizer +pdfOrganiser.header=PDF Page Organizer pdfOrganiser.submit=Rearrange Pages @@ -581,9 +581,9 @@ pdfToImage.selectText=Image Format pdfToImage.singleOrMultiple=Image result type pdfToImage.single=Single Big Image pdfToImage.multi=Multiple Images -pdfToImage.colorType=Colour type -pdfToImage.color=Colour -pdfToImage.grey=Greyscale +pdfToImage.colorType=Color type +pdfToImage.color=Color +pdfToImage.grey=Grayscale pdfToImage.blackwhite=Black and White (May lose data!) pdfToImage.submit=Convert From e9550fd6b2c0336fc0babe51bc6089c12d08f792 Mon Sep 17 00:00:00 2001 From: Jacob Braun Date: Thu, 10 Aug 2023 13:33:20 -0700 Subject: [PATCH 032/301] Add US svg Add US svg --- src/main/resources/static/images/flags/us.svg | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/resources/static/images/flags/us.svg diff --git a/src/main/resources/static/images/flags/us.svg b/src/main/resources/static/images/flags/us.svg new file mode 100644 index 000000000..a11cf5f94 --- /dev/null +++ b/src/main/resources/static/images/flags/us.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ca384218dc14ccb79fe5b0a9e88bf594192bb4ab Mon Sep 17 00:00:00 2001 From: Jacob Braun Date: Thu, 10 Aug 2023 13:33:46 -0700 Subject: [PATCH 033/301] Add US to navbar.html and distinguish English selection GB and US Add US to navbar.html and distinguish English selection GB and US --- src/main/resources/templates/fragments/navbar.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index ea253dab8..89215fcb5 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -173,7 +173,10 @@ icon Deutsch - icon English + icon English (GB) + + + icon English (US) icon Euskara From af28e30e4c4def9aa38e5bee458a217a7118f6dd Mon Sep 17 00:00:00 2001 From: adrielCarmoUFMS <141935947+adrielCarmoUFMS@users.noreply.github.com> Date: Fri, 11 Aug 2023 09:23:04 -0400 Subject: [PATCH 034/301] Update messages_pt_BR.properties updating new properties for the pt-BR language --- src/main/resources/messages_pt_BR.properties | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index 7112ddf1a..500a7d559 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -313,6 +313,7 @@ sanitizePDF.selectText.5=Remover fontes sanitizePDF.submit=Sanitizar PDF #addPageNumbers +autoCrop.title=Adicionar Números de Página addPageNumbers.title=Adicionar Números de Página addPageNumbers.header=Adicionar Números de Página addPageNumbers.selectText.1=Selecionar arquivo PDF: @@ -514,13 +515,13 @@ rotate.submit=Girar split.title=Dividir PDF split.header=Dividir PDF split.desc.1=Os números selecionados correspondem às páginas onde você deseja fazer a divisão. -split.desc.2,3,4,5,6,7,8=Por exemplo, selecionar 1,3,7-8 dividirá um documento de 10 páginas em 6 PDFs separados da seguinte forma: -split.desc.2=Documento 1: Página 1 -split.desc.3=Documento 2: Páginas 2 e 3 -split.desc.4=Documento 3: Páginas 4, 5 e 6 -split.desc.5=Documento 4: Página 7 -split.desc.6=Documento 5: Página 8 -split.desc.7=Documento 6: Páginas 9 e 10 +split.desc.2=Por exemplo, selecionar 1,3,7-8 dividirá um documento de 10 páginas em 6 PDFs separados da seguinte forma: +split.desc.3=Documento Nº1: Página 1 +split.desc.4=Documento Nº2: Páginas 2 e 3 +split.desc.5=Documento Nº3: Páginas 4, 5 e 6 +split.desc.6=Documento Nº4: Página 7 +split.desc.7=Documento Nº5: Página 8 +split.desc.8=Documento Nº6: Páginas 9 e 10 split.splitPages=Digite as páginas para a divisão: split.submit=Dividir @@ -579,6 +580,8 @@ watermark.selectText.4=Rotação (0-360) watermark.selectText.5=Espaçamento Horizontal (widthSpacer) watermark.selectText.6=Espaçamento Vertical (heightSpacer) watermark.selectText.7=Opacidade (0% - 100%) +watermark.selectText.8=Tipo de Marca d'Água +watermark.selectText.9=Imagem da Marca d'Água watermark.submit=Adicionar Marca d'Água #remove-watermark From 8a54035a9fc94bcab2abdff68872172477cf90ca Mon Sep 17 00:00:00 2001 From: adrielCarmoUFMS <141935947+adrielCarmoUFMS@users.noreply.github.com> Date: Fri, 11 Aug 2023 10:21:13 -0400 Subject: [PATCH 035/301] Update messages_pt_BR.properties Update messages_pt_BR.properties --- src/main/resources/messages_pt_BR.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index 500a7d559..21640a5db 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -220,8 +220,8 @@ home.sanitizePdf.title=Sanitizar home.sanitizePdf.desc=Remover scripts e outros elementos de arquivos PDF sanitizePdf.tags=limpar,seguro,protegido,remover-ameaças -home.URLToPDF.title=URL/Site para PDF -home.URLToPDF.desc=Converte qualquer URL http(s) para PDF +home.URLToPDF.title=Converter Site para PDF +home.URLToPDF.desc=Converte qualquer página da internet para um arquivo PDF URLToPDF.tags=captura-de-web,salvar-página,web-para-doc,arquivar home.HTMLToPDF.title=HTML para PDF From 6f325b5fdbfa8831a92d8f94b681e0cceab273f4 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sat, 12 Aug 2023 02:29:10 +0100 Subject: [PATCH 036/301] init --- build.gradle | 5 + mydatabase.mv.db | Bin 0 -> 24576 bytes mydatabase.trace.db | 382 ++++++++++++++++++ .../software/SPDF/SPdfApplication.java | 2 + .../software/SPDF/config/AppConfig.java | 11 + .../SPDF/config/CleanUrlInterceptor.java | 6 +- .../SPDF/controller/api/UserController.java | 28 ++ .../controller/web/GeneralWebController.java | 21 + .../software/SPDF/model/Authority.java | 52 +++ .../stirling/software/SPDF/model/User.java | 62 +++ .../SPDF/repository/AuthorityRepository.java | 12 + .../SPDF/repository/UserRepository.java | 12 + src/main/resources/application.properties | 15 +- src/main/resources/messages_en_GB.properties | 9 + .../resources/templates/fragments/navbar.html | 43 ++ src/main/resources/templates/home.html | 3 + src/main/resources/templates/login.html | 58 +++ 17 files changed, 718 insertions(+), 3 deletions(-) create mode 100644 mydatabase.mv.db create mode 100644 mydatabase.trace.db create mode 100644 src/main/java/stirling/software/SPDF/controller/api/UserController.java create mode 100644 src/main/java/stirling/software/SPDF/model/Authority.java create mode 100644 src/main/java/stirling/software/SPDF/model/User.java create mode 100644 src/main/java/stirling/software/SPDF/repository/AuthorityRepository.java create mode 100644 src/main/java/stirling/software/SPDF/repository/UserRepository.java create mode 100644 src/main/resources/templates/login.html diff --git a/build.gradle b/build.gradle index 5e95460f4..23fa8fd60 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,12 @@ dependencies { implementation 'org.yaml:snakeyaml:2.1' implementation 'org.springframework.boot:spring-boot-starter-web:3.1.2' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.2' + implementation 'org.springframework.boot:spring-boot-starter-security:3.1.2' testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.2' + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE' + implementation "org.springframework.boot:spring-boot-starter-data-jpa" + implementation "com.h2database:h2" + // https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4' implementation 'commons-io:commons-io:2.13.0' diff --git a/mydatabase.mv.db b/mydatabase.mv.db new file mode 100644 index 0000000000000000000000000000000000000000..aab84074cda225de298492153178d5a3242b5ee1 GIT binary patch literal 24576 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 d$|edB1@1(MVStore.java:469) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4082) + at org.h2.mvstore.db.Store.(Store.java:136) + at org.h2.engine.Database.(Database.java:324) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338) + at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:122) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:100) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.getConnectionUrl(H2ConsoleAutoConfiguration.java:94) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395) + at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) + at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575) + at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260) + at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616) + at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622) + at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.logDataSources(H2ConsoleAutoConfiguration.java:86) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.lambda$h2Console$0(H2ConsoleAutoConfiguration.java:69) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.withThreadContextClassLoader(H2ConsoleAutoConfiguration.java:78) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.h2Console(H2ConsoleAutoConfiguration.java:69) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:647) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:210) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:201) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:96) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.(ServletContextInitializerBeans.java:85) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:261) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:235) + at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:52) + at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4886) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1328) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1318) + at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) + at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) + at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) + at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) + at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:846) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1328) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1318) + at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) + at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) + at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) + at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) + at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:241) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.StandardService.startInternal(StandardService.java:428) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:918) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.startup.Tomcat.start(Tomcat.java:485) + at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123) + at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.(TomcatWebServer.java:104) + at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:489) + at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:211) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:183) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:161) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:602) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) + at stirling.software.SPDF.SPdfApplication.main(SPdfApplication.java:53) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:554) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) + ... 103 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004) + at org.h2.mvstore.FileStore.open(FileStore.java:178) + at org.h2.mvstore.FileStore.open(FileStore.java:128) + at org.h2.mvstore.MVStore.(MVStore.java:452) + ... 97 more +2023-08-12 00:40:10 database: flush +org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.get(DbException.java:212) + at org.h2.message.DbException.convert(DbException.java:395) + at org.h2.mvstore.db.Store.lambda$new$0(Store.java:125) + at org.h2.mvstore.MVStore.handleException(MVStore.java:3318) + at org.h2.mvstore.MVStore.panic(MVStore.java:593) + at org.h2.mvstore.MVStore.(MVStore.java:469) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4082) + at org.h2.mvstore.db.Store.(Store.java:136) + at org.h2.engine.Database.(Database.java:324) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338) + at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:122) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:100) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) + at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:316) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:152) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:34) + at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:119) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:239) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:216) + at org.hibernate.boot.model.relational.Database.(Database.java:45) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:230) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.(InFlightMetadataCollectorImpl.java:198) + at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:166) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1380) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1451) + at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1817) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1766) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1155) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) + at stirling.software.SPDF.SPdfApplication.main(SPdfApplication.java:53) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:554) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) + ... 64 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004) + at org.h2.mvstore.FileStore.open(FileStore.java:178) + at org.h2.mvstore.FileStore.open(FileStore.java:128) + at org.h2.mvstore.MVStore.(MVStore.java:452) + ... 58 more +2023-08-12 00:40:34 database: flush +org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.get(DbException.java:212) + at org.h2.message.DbException.convert(DbException.java:395) + at org.h2.mvstore.db.Store.lambda$new$0(Store.java:125) + at org.h2.mvstore.MVStore.handleException(MVStore.java:3318) + at org.h2.mvstore.MVStore.panic(MVStore.java:593) + at org.h2.mvstore.MVStore.(MVStore.java:469) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4082) + at org.h2.mvstore.db.Store.(Store.java:136) + at org.h2.engine.Database.(Database.java:324) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338) + at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:122) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:100) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.getConnectionUrl(H2ConsoleAutoConfiguration.java:94) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395) + at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) + at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575) + at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260) + at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616) + at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622) + at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.logDataSources(H2ConsoleAutoConfiguration.java:86) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.lambda$h2Console$0(H2ConsoleAutoConfiguration.java:69) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.withThreadContextClassLoader(H2ConsoleAutoConfiguration.java:78) + at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.h2Console(H2ConsoleAutoConfiguration.java:69) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:647) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:210) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:201) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:96) + at org.springframework.boot.web.servlet.ServletContextInitializerBeans.(ServletContextInitializerBeans.java:85) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:261) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:235) + at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:52) + at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4886) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1328) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1318) + at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) + at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) + at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) + at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) + at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:846) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1328) + at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1318) + at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) + at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) + at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) + at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) + at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:241) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.StandardService.startInternal(StandardService.java:428) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:918) + at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) + at org.apache.catalina.startup.Tomcat.start(Tomcat.java:485) + at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123) + at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.(TomcatWebServer.java:104) + at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:489) + at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:211) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:183) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:161) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:602) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) + at stirling.software.SPDF.SPdfApplication.main(SPdfApplication.java:53) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:554) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) + ... 103 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004) + at org.h2.mvstore.FileStore.open(FileStore.java:178) + at org.h2.mvstore.FileStore.open(FileStore.java:128) + at org.h2.mvstore.MVStore.(MVStore.java:452) + ... 97 more +2023-08-12 00:40:36 database: flush +org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.get(DbException.java:212) + at org.h2.message.DbException.convert(DbException.java:395) + at org.h2.mvstore.db.Store.lambda$new$0(Store.java:125) + at org.h2.mvstore.MVStore.handleException(MVStore.java:3318) + at org.h2.mvstore.MVStore.panic(MVStore.java:593) + at org.h2.mvstore.MVStore.(MVStore.java:469) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:4082) + at org.h2.mvstore.db.Store.(Store.java:136) + at org.h2.engine.Database.(Database.java:324) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338) + at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:122) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:100) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) + at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:316) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:152) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:34) + at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:119) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:239) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:216) + at org.hibernate.boot.model.relational.Database.(Database.java:45) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:230) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.(InFlightMetadataCollectorImpl.java:198) + at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:166) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1380) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1451) + at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1817) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1766) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1155) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) + at stirling.software.SPDF.SPdfApplication.main(SPdfApplication.java:53) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7]" [50000-214] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:554) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) + ... 64 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: C:/Users/systo/git/Stirling-PDF/mydatabase.mv.db [2.1.214/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:1004) + at org.h2.mvstore.FileStore.open(FileStore.java:178) + at org.h2.mvstore.FileStore.open(FileStore.java:128) + at org.h2.mvstore.MVStore.(MVStore.java:452) + ... 58 more diff --git a/src/main/java/stirling/software/SPDF/SPdfApplication.java b/src/main/java/stirling/software/SPDF/SPdfApplication.java index f95122950..f374f9b18 100644 --- a/src/main/java/stirling/software/SPDF/SPdfApplication.java +++ b/src/main/java/stirling/software/SPDF/SPdfApplication.java @@ -10,11 +10,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.core.env.Environment; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import jakarta.annotation.PostConstruct; import stirling.software.SPDF.utils.GeneralUtils; @SpringBootApplication +@EnableWebSecurity(debug = true) //@EnableScheduling public class SPdfApplication { diff --git a/src/main/java/stirling/software/SPDF/config/AppConfig.java b/src/main/java/stirling/software/SPDF/config/AppConfig.java index 430bcae89..9212bf7ec 100644 --- a/src/main/java/stirling/software/SPDF/config/AppConfig.java +++ b/src/main/java/stirling/software/SPDF/config/AppConfig.java @@ -5,6 +5,17 @@ import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { + + + @Bean(name = "loginEnabled") + public boolean loginEnabled() { + String appName = System.getProperty("login.enabled"); + if (appName == null) + appName = System.getenv("login.enabled"); + + return (appName != null) ? Boolean.valueOf(appName) : false; + } + @Bean(name = "appName") public String appName() { String appName = System.getProperty("APP_HOME_NAME"); diff --git a/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java b/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java index efa084b3b..dc2e144ba 100644 --- a/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java +++ b/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java @@ -24,8 +24,9 @@ import org.springframework.web.servlet.ModelAndView; public class CleanUrlInterceptor implements HandlerInterceptor { - private static final List ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints"); + private static final List ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints", "logout", "error"); + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { @@ -39,9 +40,12 @@ public class CleanUrlInterceptor implements HandlerInterceptor { String[] queryParameters = queryString.split("&"); for (String param : queryParameters) { String[] keyValue = param.split("="); + System.out.print("astirli " + keyValue[0]); if (keyValue.length != 2) { continue; } + System.out.print("astirli2 " + keyValue[0]); + if (ALLOWED_PARAMS.contains(keyValue[0])) { parameters.put(keyValue[0], keyValue[1]); } diff --git a/src/main/java/stirling/software/SPDF/controller/api/UserController.java b/src/main/java/stirling/software/SPDF/controller/api/UserController.java new file mode 100644 index 000000000..0fdfebb4c --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/UserController.java @@ -0,0 +1,28 @@ +package stirling.software.SPDF.controller.api; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import stirling.software.SPDF.config.security.UserService; + +@Controller +public class UserController { + + @Autowired + private UserService userService; + + @PostMapping("/register") + public String register(@RequestParam String username, @RequestParam String password, Model model) { + if(userService.usernameExists(username)) { + model.addAttribute("error", "Username already exists"); + return "register"; + } + + userService.saveUser(username, password); + return "redirect:/login?registered=true"; + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java index 4d6e991a4..7da338bac 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java @@ -16,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternUtils; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -24,10 +25,30 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; @Controller @Tag(name = "General", description = "General APIs") public class GeneralWebController { + + @GetMapping("/login") + public String login(HttpServletRequest request, Model model, Authentication authentication) { + if (authentication != null && authentication.isAuthenticated()) { + return "redirect:/"; + } + + if (request.getParameter("error") != null) { + + model.addAttribute("error", request.getParameter("error")); + } + if (request.getParameter("logout") != null) { + + model.addAttribute("logoutMessage", "You have been logged out."); + } + + return "login"; + } + @GetMapping("/pipeline") @Hidden public String pipelineForm(Model model) { diff --git a/src/main/java/stirling/software/SPDF/model/Authority.java b/src/main/java/stirling/software/SPDF/model/Authority.java new file mode 100644 index 000000000..e87ece3fe --- /dev/null +++ b/src/main/java/stirling/software/SPDF/model/Authority.java @@ -0,0 +1,52 @@ +package stirling.software.SPDF.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "authorities") +public class Authority { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "authority") + private String authority; + + @ManyToOne + @JoinColumn(name = "username") + private User user; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + +} diff --git a/src/main/java/stirling/software/SPDF/model/User.java b/src/main/java/stirling/software/SPDF/model/User.java new file mode 100644 index 000000000..2cea4d731 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/model/User.java @@ -0,0 +1,62 @@ +package stirling.software.SPDF.model; + +import java.util.Set; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +@Entity +@Table(name = "users") +public class User { + + @Id + @Column(name = "username") + private String username; + + @Column(name = "password") + private String password; + + @Column(name = "enabled") + private boolean enabled; + + @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user") + private Set authorities; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Set getAuthorities() { + return authorities; + } + + public void setAuthorities(Set authorities) { + this.authorities = authorities; + } + +} diff --git a/src/main/java/stirling/software/SPDF/repository/AuthorityRepository.java b/src/main/java/stirling/software/SPDF/repository/AuthorityRepository.java new file mode 100644 index 000000000..62f546b8a --- /dev/null +++ b/src/main/java/stirling/software/SPDF/repository/AuthorityRepository.java @@ -0,0 +1,12 @@ +package stirling.software.SPDF.repository; + +import java.util.Set; + +import org.springframework.data.jpa.repository.JpaRepository; + +import stirling.software.SPDF.model.Authority; + +public interface AuthorityRepository extends JpaRepository { + //Set findByUsername(String username); + Set findByUser_Username(String username); +} diff --git a/src/main/java/stirling/software/SPDF/repository/UserRepository.java b/src/main/java/stirling/software/SPDF/repository/UserRepository.java new file mode 100644 index 000000000..064df341c --- /dev/null +++ b/src/main/java/stirling/software/SPDF/repository/UserRepository.java @@ -0,0 +1,12 @@ +package stirling.software.SPDF.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import stirling.software.SPDF.model.User; + +public interface UserRepository extends JpaRepository { + Optional findByUsername(String username); +} + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c41183426..bf594bfcc 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -16,8 +16,11 @@ server.error.include-stacktrace=always server.error.include-exception=true server.error.include-message=always -#logging.level.org.springframework.web=DEBUG +logging.level.org.springframework.web=DEBUG +logging.level.org.springframework=DEBUG +logging.level.org.springframework.security=DEBUG +login.enabled=true server.servlet.session.tracking-modes=cookie server.servlet.context-path=${APP_ROOT_PATH:/} @@ -32,4 +35,12 @@ spring.mvc.async.request-timeout=${ASYNC_CONNECTION_TIMEOUT:300000} spring.resources.static-locations=file:customFiles/static/ #spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/ -#spring.thymeleaf.cache=false \ No newline at end of file +#spring.thymeleaf.cache=false + + +spring.datasource.url=jdbc:h2:file:./mydatabase;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.h2.console.enabled=true +spring.jpa.hibernate.ddl-auto=update diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 977260a54..182701ce8 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -55,6 +55,15 @@ settings.downloadOption.2=Open in new window settings.downloadOption.3=Download file settings.zipThreshold=Zip files when the number of downloaded files exceeds +settings.userSettings=User Settings +settings.changeUsername=New Username +settings.changeUsernameButton=Change Username +settings.password=Password +settings.oldPassword=Old password +settings.newPassword=New Password +settings.changePasswordButton=Change Password +settings.confirmNewPassword=Confirm New Password +settings.signOut=Sign Out ############# # HOME-PAGE # ############# diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index ea253dab8..4ae835705 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -338,6 +338,49 @@ + +
    +
    User Settings
    + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    - +
    From 39a187b6da89f05a2cffd3c2e0eeeac5c23e21e2 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:59:34 +0100 Subject: [PATCH 070/301] darkmode fix for account and pagenumber support filename --- .../api/other/PageNumbersController.java | 2 +- src/main/resources/application.properties | 1 - src/main/resources/messages_en_GB.properties | 3 + src/main/resources/static/css/dark-mode.css | 53 ++++++++++- src/main/resources/static/js/darkmode.js | 95 ++++++++++--------- src/main/resources/templates/account.html | 10 +- .../templates/other/add-page-numbers.html | 4 +- 7 files changed, 111 insertions(+), 57 deletions(-) diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/PageNumbersController.java b/src/main/java/stirling/software/SPDF/controller/api/other/PageNumbersController.java index 9096e64e9..92aa8d912 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/PageNumbersController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/PageNumbersController.java @@ -116,7 +116,7 @@ public class PageNumbersController { Rectangle pageSize = page.getPageSize(); PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), pdfDoc); - String text = customText != null ? customText.replace("{n}", String.valueOf(pageNumber)).replace("{total}", String.valueOf(pdfDoc.getNumberOfPages())) : String.valueOf(pageNumber); + String text = customText != null ? customText.replace("{n}", String.valueOf(pageNumber)).replace("{total}", String.valueOf(pdfDoc.getNumberOfPages())).replace("{filename}", file.getOriginalFilename().replaceFirst("[.][^.]+$", "")) : String.valueOf(pageNumber); PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA); float textWidth = font.getWidth(text, fontSize); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 20638f7df..da508e200 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -20,7 +20,6 @@ server.error.include-message=always #logging.level.org.springframework=DEBUG #logging.level.org.springframework.security=DEBUG -#login.enabled=true server.servlet.session.tracking-modes=cookie server.servlet.context-path=${APP_ROOT_PATH:/} diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 58fc107fa..5ca0bd74e 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -374,6 +374,9 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers diff --git a/src/main/resources/static/css/dark-mode.css b/src/main/resources/static/css/dark-mode.css index 0e78e4aef..cf2e028d3 100644 --- a/src/main/resources/static/css/dark-mode.css +++ b/src/main/resources/static/css/dark-mode.css @@ -1,5 +1,5 @@ /* Dark Mode Styles */ -body { +body, select, textarea { --body-background-color: 51, 51, 51; --base-font-color: 255, 255, 255; background-color: rgb(var(--body-background-color)) !important; @@ -41,4 +41,53 @@ body { .favorite-icon img { filter: brightness(0) invert(1) !important; -} \ No newline at end of file +} +table thead { + background-color: #333 !important; + border: 1px solid #444; +} +table th, table td { + border: 1px solid #444 !important; + color: white; +} +.btn { + background-color: #444 !important; + border: none; + color: #fff !important; +} +.btn-primary { + background-color: #007bff !important; + border: none; + color: #fff !important; +} +.btn-secondary { + background-color: #6c757d !important; + border: none; + color: #fff !important; +} +.btn-info { + background-color: #17a2b8 !important; + border: none; + color: #fff !important; +} +.btn-danger { + background-color: #dc3545 !important; + border: none; + color: #fff !important; +} +.btn-outline-secondary { + color: #fff !important; + border-color: #fff; +} +.btn-outline-secondary:hover { + background-color: #444 !important; + color: #007bff !important; + border-color: #007bff; +} +.blackwhite-icon { + filter: brightness(0) invert(1); +} +hr { + border-color: rgba(255, 255, 255, 0.6); /* semi-transparent white */ + background-color: rgba(255, 255, 255, 0.6); /* for some browsers that might use background instead of border for
    */ +} diff --git a/src/main/resources/static/js/darkmode.js b/src/main/resources/static/js/darkmode.js index c91bfa689..9139e801b 100644 --- a/src/main/resources/static/js/darkmode.js +++ b/src/main/resources/static/js/darkmode.js @@ -1,6 +1,44 @@ var toggleCount = 0; var lastToggleTime = Date.now(); +var elements = { + lightModeStyles: null, + darkModeStyles: null, + rainbowModeStyles: null, + darkModeIcon: null +}; + +function getElements() { + elements.lightModeStyles = document.getElementById("light-mode-styles"); + elements.darkModeStyles = document.getElementById("dark-mode-styles"); + elements.rainbowModeStyles = document.getElementById("rainbow-mode-styles"); + elements.darkModeIcon = document.getElementById("dark-mode-icon"); +} + +function setMode(mode) { + elements.lightModeStyles.disabled = mode !== "off"; + elements.darkModeStyles.disabled = mode !== "on"; + elements.rainbowModeStyles.disabled = mode !== "rainbow"; + + if (mode === "on") { + elements.darkModeIcon.src = "moon.svg"; + // Add the table-dark class to tables for dark mode + var tables = document.querySelectorAll('.table'); + tables.forEach(table => { + table.classList.add('table-dark'); + }); + } else if (mode === "off") { + elements.darkModeIcon.src = "sun.svg"; + // Remove the table-dark class for light mode + var tables = document.querySelectorAll('.table-dark'); + tables.forEach(table => { + table.classList.remove('table-dark'); + }); + } else if (mode === "rainbow") { + elements.darkModeIcon.src = "rainbow.svg"; + } +} + function toggleDarkMode() { var currentTime = Date.now(); if (currentTime - lastToggleTime < 1000) { @@ -10,67 +48,32 @@ function toggleDarkMode() { } lastToggleTime = currentTime; - var lightModeStyles = document.getElementById("light-mode-styles"); - var darkModeStyles = document.getElementById("dark-mode-styles"); - var rainbowModeStyles = document.getElementById("rainbow-mode-styles"); - var darkModeIcon = document.getElementById("dark-mode-icon"); - if (toggleCount >= 18) { localStorage.setItem("dark-mode", "rainbow"); - lightModeStyles.disabled = true; - darkModeStyles.disabled = true; - rainbowModeStyles.disabled = false; - darkModeIcon.src = "rainbow.svg"; + setMode("rainbow"); } else if (localStorage.getItem("dark-mode") == "on") { localStorage.setItem("dark-mode", "off"); - lightModeStyles.disabled = false; - darkModeStyles.disabled = true; - rainbowModeStyles.disabled = true; - darkModeIcon.src = "sun.svg"; + setMode("off"); } else { localStorage.setItem("dark-mode", "on"); - lightModeStyles.disabled = true; - darkModeStyles.disabled = false; - rainbowModeStyles.disabled = true; - darkModeIcon.src = "moon.svg"; + setMode("on"); } } document.addEventListener("DOMContentLoaded", function() { - var lightModeStyles = document.getElementById("light-mode-styles"); - var darkModeStyles = document.getElementById("dark-mode-styles"); - var rainbowModeStyles = document.getElementById("rainbow-mode-styles"); - var darkModeIcon = document.getElementById("dark-mode-icon"); + getElements(); - if (localStorage.getItem("dark-mode") == "on") { - lightModeStyles.disabled = true; - darkModeStyles.disabled = false; - rainbowModeStyles.disabled = true; - darkModeIcon.src = "moon.svg"; - } else if (localStorage.getItem("dark-mode") == "off") { - lightModeStyles.disabled = false; - darkModeStyles.disabled = true; - rainbowModeStyles.disabled = true; - darkModeIcon.src = "sun.svg"; - } else if (localStorage.getItem("dark-mode") == "rainbow") { - lightModeStyles.disabled = true; - darkModeStyles.disabled = true; - rainbowModeStyles.disabled = false; - darkModeIcon.src = "rainbow.svg"; + var currentMode = localStorage.getItem("dark-mode"); + if (currentMode === "on" || currentMode === "off" || currentMode === "rainbow") { + setMode(currentMode); + } else if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { + setMode("on"); } else { - if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { - darkModeStyles.disabled = false; - rainbowModeStyles.disabled = true; - darkModeIcon.src = "moon.svg"; - } else { - darkModeStyles.disabled = true; - rainbowModeStyles.disabled = true; - darkModeIcon.src = "sun.svg"; - } + setMode("off"); } document.getElementById("dark-mode-toggle").addEventListener("click", function(event) { event.preventDefault(); toggleDarkMode(); }); -}); \ No newline at end of file +}); diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html index ceba9cc4f..bd01c24ef 100644 --- a/src/main/resources/templates/account.html +++ b/src/main/resources/templates/account.html @@ -30,7 +30,7 @@
    - +
    @@ -44,7 +44,7 @@
    - +
    @@ -70,13 +70,13 @@
    diff --git a/src/main/resources/templates/other/add-page-numbers.html b/src/main/resources/templates/other/add-page-numbers.html index 8972d1cc4..9111ab44f 100644 --- a/src/main/resources/templates/other/add-page-numbers.html +++ b/src/main/resources/templates/other/add-page-numbers.html @@ -103,12 +103,12 @@ + th:placeholder="#{addPageNumbers.numberPagesDesc}" />
    + th:placeholder="#{addPageNumbers.customNumberDesc}" />
    From e88a780efeed53a6626fbcaa0ba185fbb9301449 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sat, 19 Aug 2023 17:00:34 +0100 Subject: [PATCH 071/301] lang --- src/main/resources/messages_ar_AR.properties | 26 +++++----------- src/main/resources/messages_ca_CA.properties | 26 +++++----------- src/main/resources/messages_de_DE.properties | 26 +++++----------- src/main/resources/messages_en_US.properties | 26 +++++----------- src/main/resources/messages_es_ES.properties | 26 +++++----------- src/main/resources/messages_eu_ES.properties | 26 +++++----------- src/main/resources/messages_fr_FR.properties | 32 +++++--------------- src/main/resources/messages_it_IT.properties | 26 +++++----------- src/main/resources/messages_ja_JP.properties | 26 +++++----------- src/main/resources/messages_ko_KR.properties | 26 +++++----------- src/main/resources/messages_nl_NL.properties | 18 +++++++---- src/main/resources/messages_pl_PL.properties | 26 +++++----------- src/main/resources/messages_pt_BR.properties | 26 +++++----------- src/main/resources/messages_ro_RO.properties | 26 +++++----------- src/main/resources/messages_ru_RU.properties | 26 +++++----------- src/main/resources/messages_sv_SE.properties | 26 +++++----------- src/main/resources/messages_zh_CN.properties | 26 +++++----------- 17 files changed, 124 insertions(+), 316 deletions(-) diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index 7f9cd9cbb..24129d2d4 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=\u0641\u062A\u062D \u0641\u064A \u0646\u0641\u0633 \u0 settings.downloadOption.2=\u0641\u062A\u062D \u0641\u064A \u0646\u0627\u0641\u0630\u0629 \u062C\u062F\u064A\u062F\u0629 settings.downloadOption.3=\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u0645\u0644\u0641 settings.zipThreshold=\u0645\u0644\u0641\u0627\u062A \u0645\u0636\u063A\u0648\u0637\u0629 \u0639\u0646\u062F \u062A\u062C\u0627\u0648\u0632 \u0639\u062F\u062F \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u0645 \u062A\u0646\u0632\u064A\u0644\u0647\u0627 -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=إضافة صورة #merge merge.title=دمج merge.header=دمج ملفات PDF متعددة (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=دمج @@ -676,9 +667,6 @@ watermark.selectText.4=دوران (0-360): watermark.selectText.5=widthSpacer (مسافة بين كل علامة مائية أفقيًا): watermark.selectText.6=heightSpacer (مسافة بين كل علامة مائية عموديًا): watermark.selectText.7=\u0627\u0644\u062A\u0639\u062A\u064A\u0645 (0\u066A - 100\u066A): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=إضافة علامة مائية diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties index 68d8b4661..6319e5a05 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Obre mateixa finestra settings.downloadOption.2=Obre mateixa finestra settings.downloadOption.3=Descarrega Arxiu settings.zipThreshold=Comprimiu els fitxers quan el nombre de fitxers baixats superi -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Afegir Imatge #merge merge.title=Fusiona merge.header=Fusiona múltiples PDFs (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Fusiona @@ -676,9 +667,6 @@ watermark.selectText.4=Rotació (0-360): watermark.selectText.5=separació d'amplada (Espai horitzontal entre cada Marca d'Aigua): watermark.selectText.6=separació d'alçada (Espai vertical entre cada Marca d'Aigua): watermark.selectText.7=Opacitat (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Afegir Marca d'Aigua diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties index 35043038c..11cf141d7 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Im selben Fenster öffnen settings.downloadOption.2=In neuem Fenster öffnen settings.downloadOption.3=Datei herunterladen settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Bild hinzufügen #merge merge.title=Zusammenführen merge.header=Mehrere PDFs zusammenführen (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Zusammenführen @@ -676,9 +667,6 @@ watermark.selectText.4=Drehung (0-360): watermark.selectText.5=breiteSpacer (horizontaler Abstand zwischen den einzelnen Wasserzeichen): watermark.selectText.6=höheSpacer (vertikaler Abstand zwischen den einzelnen Wasserzeichen): watermark.selectText.7=Deckkraft (0% - 100 %): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Wasserzeichen hinzufügen diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 778629bfe..cf228aad0 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Open in same window settings.downloadOption.2=Open in new window settings.downloadOption.3=Download file settings.zipThreshold=Zip files when the number of downloaded files exceeds -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Add image #merge merge.title=Merge merge.header=Merge multiple PDFs (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Merge @@ -676,9 +667,6 @@ watermark.selectText.4=Rotation (0-360): watermark.selectText.5=widthSpacer (Space between each watermark horizontally): watermark.selectText.6=heightSpacer (Space between each watermark vertically): watermark.selectText.7=Opacity (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Add Watermark diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index 6199dad72..35065a1a7 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -31,9 +31,6 @@ sizes.medium=Mediano sizes.large=Grande sizes.x-large=Extra grande error.pdfPassword=El documento PDF está protegido con contraseña y no se ha proporcionado o es incorrecta -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Abrir en la misma ventana settings.downloadOption.2=Abrir en una nueva ventana settings.downloadOption.3=Descargar el fichero settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descargados -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Posición addPageNumbers.selectText.4=Número de inicio addPageNumbers.selectText.5=Páginas a numerar addPageNumbers.selectText.6=Texto personalizado +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Añadir Números de Página @@ -571,9 +565,6 @@ addImage.submit=Añadir imagen #merge merge.title=Unir merge.header=Unir múltiples PDFs (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Unir @@ -676,9 +667,6 @@ watermark.selectText.4=Rotación (0-360): watermark.selectText.5=Ancho (Espacio entre cada marca de agua horizontalmente): watermark.selectText.6=Alto (Espacio entre cada marca de agua verticalmente): watermark.selectText.7=Opacidad (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Añadir marca de agua diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties index 47aa19900..22703f65b 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=PDF dokumentua pasahitzarekin babestuta dago eta pasahitza ez da sartu edo akastuna da -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Ireki leiho berean settings.downloadOption.2=Ireki leiho berrian settings.downloadOption.3=Deskargatu fitxategia settings.zipThreshold=ZIP fitxategiak deskargatutako fitxategi kopurua gainditzen denean -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Gehitu irudia #merge merge.title=Elkartu merge.header=Elkartu zenbait PDF (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Elkartu @@ -676,9 +667,6 @@ watermark.selectText.4=Errotazioa (0-360): watermark.selectText.5=Zabalera (ur-marka bakoitzaren arteko espazioa horizontalean): watermark.selectText.6=Altuera (ur-marka bakoitzaren arteko espazioa bertikalean): watermark.selectText.7=Opakutasuna (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Gehitu ur-marka diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index d35a801d8..521bd7847 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -31,9 +31,6 @@ sizes.medium=Moyen sizes.large=Grand sizes.x-large=Très grand error.pdfPassword=Le document PDF est protégé par un mot de passe et le mot de passe n\u2019a pas été fourni ou était incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Ouvrir dans la même fenêtre settings.downloadOption.2=Ouvrir dans une nouvelle fenêtre settings.downloadOption.3=Télécharger le fichier settings.zipThreshold=Compresser les fichiers en ZIP lorsque le nombre de fichiers téléchargés dépasse -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -330,9 +318,6 @@ pdfToSinglePage.submit=Convertir en une seule page #pageExtracter -########################## -### TODO: Translate ### -########################## pageExtracter.title=Extract Pages pageExtracter.header=Extract Pages pageExtracter.submit=Extract @@ -389,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Numéro de départ addPageNumbers.selectText.5=Pages à numéroter addPageNumbers.selectText.6=Texte personnalisé +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Ajouter les numéros de page @@ -574,9 +565,6 @@ addImage.submit=Ajouter une image #merge merge.title=Fusionner merge.header=Fusionner plusieurs PDF -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Fusionner @@ -594,9 +582,6 @@ multiTool.header=Outil multifonction PDF #pageRemover -########################## -### TODO: Translate ### -########################## pageRemover.title=Page Remover pageRemover.header=PDF Page remover pageRemover.pagesToDelete=Pages to delete (Enter a comma-separated list of page numbers) : @@ -733,9 +718,6 @@ changeMetadata.submit=Modifier #xlsToPdf -########################## -### TODO: Translate ### -########################## xlsToPdf.title=Excel to PDF xlsToPdf.header=Excel to PDF xlsToPdf.selectText.1=Select XLS or XLSX Excel sheet to convert diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index 219a36855..17f06989a 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Apri in questa finestra settings.downloadOption.2=Apri in una nuova finestra settings.downloadOption.3=Scarica file settings.zipThreshold=Comprimi file in .zip quando il numero di download supera -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Aggiungi immagine #merge merge.title=Unisci merge.header=Unisci 2 o più PDF -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Unisci @@ -676,9 +667,6 @@ watermark.selectText.4=Rotazione (0-360): watermark.selectText.5=spazio orizzontale (tra ogni filigrana): watermark.selectText.6=spazio verticale (tra ogni filigrana): watermark.selectText.7=Opacità (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Aggiungi Filigrana diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index 5847a5f67..534523c82 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=PDFにパスワードが設定されてますが、パスワードが入力されてないか間違ってます。 -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=同じウィンドウで開く settings.downloadOption.2=新しいウィンドウで開く settings.downloadOption.3=ファイルをダウンロード settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=画像の追加 #merge merge.title=結合 merge.header=複数のPDFを結合 (2ファイル以上) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=結合 @@ -676,9 +667,6 @@ watermark.selectText.4=回転 (0-360): watermark.selectText.5=幅スペース (各透かし間の水平方向のスペース): watermark.selectText.6=高さスペース (各透かし間の垂直方向のスペース): watermark.selectText.7=不透明度 (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=透かしを追加 diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index 889929f8b..2ca0e8e11 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=현재 창에서 열기 settings.downloadOption.2=새 창에서 열기 settings.downloadOption.3=다운로드 settings.zipThreshold=다운로드한 파일 수가 초과된 경우 파일 압축하기 -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=이미지 추가 #merge merge.title=병합 merge.header=여러 개의 PDF 병합 (2개 이상) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=병합 @@ -676,9 +667,6 @@ watermark.selectText.4=회전 각도 (0-360): watermark.selectText.5=가로 간격 (각 워터마크 사이의 가로 공간): watermark.selectText.6=세로 간격 (각 워터마크 사이의 세로 공간): watermark.selectText.7=투명도 (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=워터마크 추가 diff --git a/src/main/resources/messages_nl_NL.properties b/src/main/resources/messages_nl_NL.properties index 13fc27023..fae05b897 100644 --- a/src/main/resources/messages_nl_NL.properties +++ b/src/main/resources/messages_nl_NL.properties @@ -1,7 +1,7 @@ ########### # Generic # ########### -# the direction that the language is written (ltr = left to right, rtl = right to left) +# the direction that the language is written (ltr=left to right, rtl = right to left) language.direction=ltr pdfPrompt=Selecteer PDF(s) @@ -65,7 +65,7 @@ account.title=Account instellingen account.accountSettings=Account instellingen account.adminSettings=Beheerdersinstellingen - Gebruikers bekijken en toevoegen account.userControlSettings=Gebruikerscontrole instellingen -account.changeUsername=Nieuwe gebruikersnaam +account.changeUsername=Wijzig gebruikersnaam account.changeUsername=Wijzig gebruikersnaam account.password=Bevestigingswachtwoord account.oldPassword=Oud wachtwoord @@ -374,6 +374,12 @@ addPageNumbers.selectText.3=Positie addPageNumbers.selectText.4=Startnummer addPageNumbers.selectText.5=Pagina''s om te nummeren addPageNumbers.selectText.6=Aangepaste tekst +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Paginanummers toevoegen @@ -500,7 +506,7 @@ ScannerImageSplit.selectText.8=Stelt de minimale contour oppervlakte drempel in ScannerImageSplit.selectText.9=Randgrootte: ScannerImageSplit.selectText.10=Stelt de grootte van de toegevoegde en verwijderde rand in om witte randen in de uitvoer te voorkomen (standaard: 1). - + #OCR ocr.title=OCR / Scan opruimen ocr.header=Scans opruimen / OCR (Optical Character Recognition) @@ -613,8 +619,8 @@ imageToPDF.selectText.2=PDF automatisch draaien imageToPDF.selectText.3=Meervoudige bestandslogica (Alleen ingeschakeld bij werken met meerdere afbeeldingen) imageToPDF.selectText.4=Voeg samen in één PDF imageToPDF.selectText.5=Zet om naar afzonderlijke PDF''s - - + + #pdfToImage pdfToImage.title=PDF naar afbeelding pdfToImage.header=PDF naar afbeelding @@ -692,7 +698,7 @@ removePassword.submit=Verwijderen #changeMetadata -changeMetadata.title=Metadata wijzigen +changeMetadata.title=Titel: changeMetadata.header=Metadata wijzigen changeMetadata.selectText.1=Pas de variabelen aan die je wilt wijzigen changeMetadata.selectText.2=Verwijder alle metadata diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index a386b8dd6..d327b9e7d 100644 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=Dokument PDF jest zabezpieczony hasłem, musisz podać prawidłowe hasło. -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Otwórz w tym samym oknie settings.downloadOption.2=Otwórz w nowym oknie settings.downloadOption.3=Pobierz plik settings.zipThreshold=Spakuj pliki, gdy liczba pobranych plików przekroczy -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Dodaj obraz #merge merge.title=Połącz merge.header=Połącz wiele dokumentów PDF (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Połącz @@ -676,9 +667,6 @@ watermark.selectText.4=Obrót (0-360): watermark.selectText.5=Odstęp w poziomie (odstęp między każdym znakiem wodnym w poziomie): watermark.selectText.6=Odstęp w pionie (odstęp między każdym znakiem wodnym w pionie): watermark.selectText.7=Nieprzezroczystość (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Dodaj znak wodny diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index 1e334c0d4..79f9dc181 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -31,9 +31,6 @@ sizes.medium=Médio sizes.large=Grande sizes.x-large=Muito grande error.pdfPassword=O documento PDF está protegido por senha e a senha não foi fornecida ou está incorreta -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Abrir na mesma janela settings.downloadOption.2=Abrir em nova janela settings.downloadOption.3=⇬ Fazer download do arquivo settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados exceder -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Posição addPageNumbers.selectText.4=Número Inicial addPageNumbers.selectText.5=Páginas a Numerar addPageNumbers.selectText.6=Texto Personalizado +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Adicionar Números de Página @@ -527,9 +521,6 @@ ocr.selectText.8=Normal (gerará um erro se o PDF já contiver texto) ocr.selectText.9=Configurações adicionais ocr.selectText.10=Modo OCR ocr.selectText.11=Remover imagens após o OCR (remove TODAS as imagens, útil apenas como parte do processo de conversão) -########################## -### TODO: Translate ### -########################## ocr.selectText.12=Render Type (Advanced) ocr.help=Por favor, leia a documentação sobre como usar isso para outros idiomas e/ou fora do ambiente Docker ocr.credit=Este serviço usa OCRmyPDF e Tesseract para OCR. @@ -574,9 +565,6 @@ addImage.submit=Adicionar Imagem #merge merge.title=Mesclar merge.header=Mesclar Vários PDFs (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Mesclar diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties index f03af6193..11c66c75b 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Deschide în aceeași fereastră settings.downloadOption.2=Deschide într-o fereastră nouă settings.downloadOption.3=Descarcă fișierul settings.zipThreshold=Împachetează fișierele când numărul de fișiere descărcate depășește -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Adăugare imagine #merge merge.title=Unire merge.header=Unirea mai multor PDF-uri (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Unire @@ -676,9 +667,6 @@ watermark.selectText.4=Rotire (0-360): watermark.selectText.5=widthSpacer (Spațiu între fiecare filigran pe orizontală): watermark.selectText.6=heightSpacer (Spațiu între fiecare filigran pe verticală): watermark.selectText.7=Opacitate (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Adăugați Filigran diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties index 425b2a0a5..af466cad0 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Открыть в том же окне settings.downloadOption.2=Открыть в новом окне settings.downloadOption.3=Загрузить файл settings.zipThreshold=Zip-файлы, когда количество загруженных файлов превышает -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Добавить изображение #merge merge.title=Объединить merge.header=Объединение нескольких PDF-файлов (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Объединить @@ -676,9 +667,6 @@ watermark.selectText.4=Поворот (0-360): watermark.selectText.5=widthSpacer (пробел между каждым водяным знаком по горизонтали): watermark.selectText.6=heightSpacer (пробел между каждым водяным знаком по вертикали): watermark.selectText.7=Непрозрачность (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Добавить водяной знак diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties index 847f94a66..49a57919c 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=Öppnas i samma fönster settings.downloadOption.2=Öppna i nytt fönster settings.downloadOption.3=Ladda ner fil settings.zipThreshold=Zip-filer när antalet nedladdade filer överskrider -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=Lägg till bild #merge merge.title=Sammanfoga merge.header=Slå samman flera PDF-filer (2+) -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=Slå samman @@ -676,9 +667,6 @@ watermark.selectText.4=Rotation (0-360): watermark.selectText.5=widthSpacer (mellanrum mellan varje vattenstämpel horisontellt): watermark.selectText.6=heightSpacer (mellanrum mellan varje vattenstämpel vertikalt): watermark.selectText.7=Opacitet (0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=Lägg till vattenstämpel diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties index 82c047ea9..5d1d1c1db 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -31,9 +31,6 @@ sizes.medium=Medium sizes.large=Large sizes.x-large=X-Large error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect -########################## -### TODO: Translate ### -########################## delete=Delete username=Username password=Password @@ -61,20 +58,14 @@ settings.downloadOption.1=在同一窗口打开 settings.downloadOption.2=在新窗口中打开 settings.downloadOption.3=下载文件 settings.zipThreshold=当下载的文件数量超过限制时,将文件压缩。 -########################## -### TODO: Translate ### -########################## settings.signOut=Sign Out settings.accountSettings=Account Settings -########################## -### TODO: Translate ### -########################## account.title=Account Settings account.accountSettings=Account Settings account.adminSettings=Admin Settings - View and Add Users account.userControlSettings=User Control Settings -account.changeUsername=New Username +account.changeUsername=Change Username account.changeUsername=Change Username account.password=Confirmation Password account.oldPassword=Old password @@ -91,9 +82,6 @@ account.syncToBrowser=Sync Account -> Browser account.syncToAccount=Sync Account <- Browser -########################## -### TODO: Translate ### -########################## adminUserSettings.title=User Control Settings adminUserSettings.header=Admin User Control Settings adminUserSettings.admin=Admin @@ -386,6 +374,12 @@ addPageNumbers.selectText.3=Position addPageNumbers.selectText.4=Starting Number addPageNumbers.selectText.5=Pages to Number addPageNumbers.selectText.6=Custom Text +########################## +### TODO: Translate ### +########################## +addPageNumbers.customTextDesc=Custom Text +addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc +addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n} addPageNumbers.submit=Add Page Numbers @@ -571,9 +565,6 @@ addImage.submit=添加图片 #merge merge.title=合并 merge.header=合并多个PDF(2个以上)。 -########################## -### TODO: Translate ### -########################## merge.sortByName=Sort by name merge.sortByDate=Sort by date merge.submit=合并 @@ -676,9 +667,6 @@ watermark.selectText.4=旋转(0-360): watermark.selectText.5=widthSpacer(水平方向上每个水印之间的空间): watermark.selectText.6=heightSpacer(每个水印之间的垂直空间): watermark.selectText.7=透明度(0% - 100%): -########################## -### TODO: Translate ### -########################## watermark.selectText.8=Watermark Type: watermark.selectText.9=Watermark Image: watermark.submit=添加水印 From 7c26c56210ef09691c9de897029f4cd6bb94e571 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 20 Aug 2023 21:57:19 +0100 Subject: [PATCH 072/301] test --- src/main/resources/static/css/home.css | 2 +- .../resources/static/js/draggable-utils.js | 20 ++--- src/main/resources/static/js/fileInput.js | 6 +- src/main/resources/static/js/homecard.js | 2 +- .../resources/static/js/languageSelection.js | 53 +++++++------ src/main/resources/static/js/pipeline.js | 2 +- src/main/resources/static/js/search.js | 2 +- src/main/resources/templates/account.html | 18 ++--- src/main/resources/templates/addUsers.html | 6 +- .../resources/templates/auto-split-pdf.html | 2 +- .../templates/convert/img-to-pdf.html | 8 +- .../templates/convert/pdf-to-img.html | 8 +- .../convert/pdf-to-presentation.html | 2 +- .../templates/convert/pdf-to-text.html | 2 +- .../templates/convert/pdf-to-word.html | 2 +- .../resources/templates/extract-page.html | 2 +- .../resources/templates/fragments/card.html | 4 +- .../resources/templates/fragments/common.html | 33 ++++---- .../templates/fragments/errorBanner.html | 2 +- .../fragments/errorBannerPerPage.html | 6 +- .../templates/fragments/langAndDarkMode.html | 75 +++++++++++++++++++ .../resources/templates/fragments/navbar.html | 68 ++++++++--------- .../templates/fragments/navbarEntry.html | 2 +- src/main/resources/templates/home.html | 2 +- src/main/resources/templates/login.html | 10 +-- src/main/resources/templates/merge-pdfs.html | 6 +- .../templates/other/add-page-numbers.html | 10 +-- .../templates/other/change-metadata.html | 34 ++++----- .../templates/other/extract-image-scans.html | 10 +-- .../templates/other/extract-images.html | 2 +- .../templates/other/multi-page-layout.html | 2 +- .../resources/templates/other/ocr-pdf.html | 6 +- .../templates/other/remove-blanks.html | 4 +- .../templates/other/scale-pages.html | 4 +- .../resources/templates/pdf-organizer.html | 4 +- src/main/resources/templates/pipeline.html | 8 +- .../resources/templates/remove-pages.html | 2 +- .../templates/security/add-password.html | 12 +-- .../templates/security/add-watermark.html | 20 ++--- .../templates/security/cert-sign.html | 24 +++--- .../security/change-permissions.html | 6 +- .../templates/security/remove-password.html | 6 +- .../templates/security/remove-watermark.html | 6 +- .../templates/security/sanitize-pdf.html | 4 +- src/main/resources/templates/split-pdfs.html | 2 +- 45 files changed, 297 insertions(+), 214 deletions(-) create mode 100644 src/main/resources/templates/fragments/langAndDarkMode.html diff --git a/src/main/resources/static/css/home.css b/src/main/resources/static/css/home.css index 998278e16..f75491674 100644 --- a/src/main/resources/static/css/home.css +++ b/src/main/resources/static/css/home.css @@ -14,7 +14,7 @@ .features-container { display: grid; - grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr)); + grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr)); gap: 25px 30px; } diff --git a/src/main/resources/static/js/draggable-utils.js b/src/main/resources/static/js/draggable-utils.js index f90a80f1b..4dadf920b 100644 --- a/src/main/resources/static/js/draggable-utils.js +++ b/src/main/resources/static/js/draggable-utils.js @@ -13,12 +13,12 @@ const DraggableUtils = { listeners: { move: (event) => { const target = event.target; - const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx; - const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy; + const x = (parseFloat(target.getAttribute('data-bs-x')) || 0) + event.dx; + const y = (parseFloat(target.getAttribute('data-bs-y')) || 0) + event.dy; target.style.transform = `translate(${x}px, ${y}px)`; - target.setAttribute('data-x', x); - target.setAttribute('data-y', y); + target.setAttribute('data-bs-x', x); + target.setAttribute('data-bs-y', y); this.onInteraction(target); }, @@ -29,8 +29,8 @@ const DraggableUtils = { listeners: { move: (event) => { var target = event.target - var x = (parseFloat(target.getAttribute('data-x')) || 0) - var y = (parseFloat(target.getAttribute('data-y')) || 0) + var x = (parseFloat(target.getAttribute('data-bs-x')) || 0) + var y = (parseFloat(target.getAttribute('data-bs-y')) || 0) // check if control key is pressed if (event.ctrlKey) { @@ -58,8 +58,8 @@ const DraggableUtils = { target.style.transform = 'translate(' + x + 'px,' + y + 'px)' - target.setAttribute('data-x', x) - target.setAttribute('data-y', y) + target.setAttribute('data-bs-x', x) + target.setAttribute('data-bs-y', y) target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height) this.onInteraction(target); @@ -86,8 +86,8 @@ const DraggableUtils = { const x = 0; const y = 20; createdCanvas.style.transform = `translate(${x}px, ${y}px)`; - createdCanvas.setAttribute('data-x', x); - createdCanvas.setAttribute('data-y', y); + createdCanvas.setAttribute('data-bs-x', x); + createdCanvas.setAttribute('data-bs-y', y); createdCanvas.onclick = e => this.onInteraction(e.target); diff --git a/src/main/resources/static/js/fileInput.js b/src/main/resources/static/js/fileInput.js index 7825af8b3..12d50b3fe 100644 --- a/src/main/resources/static/js/fileInput.js +++ b/src/main/resources/static/js/fileInput.js @@ -3,9 +3,9 @@ document.addEventListener('DOMContentLoaded', function() { }); function setupFileInput(chooser) { - const elementId = chooser.getAttribute('data-element-id'); - const filesSelected = chooser.getAttribute('data-files-selected'); - const pdfPrompt = chooser.getAttribute('data-pdf-prompt'); + const elementId = chooser.getAttribute('data-bs-element-id'); + const filesSelected = chooser.getAttribute('data-bs-files-selected'); + const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt'); let allFiles = []; let overlay; diff --git a/src/main/resources/static/js/homecard.js b/src/main/resources/static/js/homecard.js index 72997a029..d0d561854 100644 --- a/src/main/resources/static/js/homecard.js +++ b/src/main/resources/static/js/homecard.js @@ -10,7 +10,7 @@ function filterCards() { // Get the navbar tags associated with the card var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`); - var navbarTags = navbarItem ? navbarItem.getAttribute('data-tags') : ''; + var navbarTags = navbarItem ? navbarItem.getAttribute('data-bs-tags') : ''; var content = title + ' ' + text + ' ' + navbarTags; diff --git a/src/main/resources/static/js/languageSelection.js b/src/main/resources/static/js/languageSelection.js index e9d141f5e..359a2be35 100644 --- a/src/main/resources/static/js/languageSelection.js +++ b/src/main/resources/static/js/languageSelection.js @@ -14,33 +14,40 @@ document.addEventListener('DOMContentLoaded', function() { }); function handleDropdownItemClick(event) { - event.preventDefault(); - const languageCode = this.dataset.languageCode; - localStorage.setItem('languageCode', languageCode); + event.preventDefault(); + const languageCode = event.currentTarget.dataset.bsLanguageCode; // change this to event.currentTarget + if (languageCode) { + localStorage.setItem('languageCode', languageCode); - const currentUrl = window.location.href; - if (currentUrl.indexOf('?lang=') === -1) { - window.location.href = currentUrl + '?lang=' + languageCode; - } else { - window.location.href = currentUrl.replace(/\?lang=\w{2,}/, '?lang=' + languageCode); - } + const currentUrl = window.location.href; + if (currentUrl.indexOf('?lang=') === -1) { + window.location.href = currentUrl + '?lang=' + languageCode; + } else { + window.location.href = currentUrl.replace(/\?lang=\w{2,}/, '?lang=' + languageCode); + } + } else { + console.error("Language code is not set for this item."); // for debugging + } } -$(document).ready(function() { - $(".nav-item.dropdown").each(function() { - var $dropdownMenu = $(this).find(".dropdown-menu"); - if ($dropdownMenu.children().length <= 2 && $dropdownMenu.children("hr.dropdown-divider").length === $dropdownMenu.children().length) { - $(this).prev('.nav-item.nav-item-separator').remove(); - $(this).remove(); - } - }); +document.addEventListener('DOMContentLoaded', function() { + document.querySelectorAll('.nav-item.dropdown').forEach((element) => { + const dropdownMenu = element.querySelector(".dropdown-menu"); + if (dropdownMenu.children.length <= 2 && dropdownMenu.querySelectorAll("hr.dropdown-divider").length === dropdownMenu.children.length) { + if (element.previousElementSibling && element.previousElementSibling.classList.contains('nav-item') && element.previousElementSibling.classList.contains('nav-item-separator')) { + element.previousElementSibling.remove(); + } + element.remove(); + } + }); + //Sort languages by alphabet - var list = $('.dropdown-menu[aria-labelledby="languageDropdown"]').children("a"); + const list = Array.from(document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').children).filter(child => child.matches('a')); list.sort(function(a, b) { - var A = $(a).text().toUpperCase(); - var B = $(b).text().toUpperCase(); - return (A < B) ? -1 : (A > B) ? 1 : 0; - }) - .appendTo('.dropdown-menu[aria-labelledby="languageDropdown"]'); + var A = a.textContent.toUpperCase(); + var B = b.textContent.toUpperCase(); + return (A < B) ? -1 : (A > B) ? 1 : 0; + }).forEach(node => document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').appendChild(node)); + }); \ No newline at end of file diff --git a/src/main/resources/static/js/pipeline.js b/src/main/resources/static/js/pipeline.js index 8b2c263da..06810743d 100644 --- a/src/main/resources/static/js/pipeline.js +++ b/src/main/resources/static/js/pipeline.js @@ -241,7 +241,7 @@ document.getElementById('addOperationBtn').addEventListener('click', function() if (parameter.name === 'fileInput') return; let parameterDiv = document.createElement('div'); - parameterDiv.className = "form-group"; + parameterDiv.className = "mb-3"; let parameterLabel = document.createElement('label'); parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `; diff --git a/src/main/resources/static/js/search.js b/src/main/resources/static/js/search.js index a40072069..5dd4acf5e 100644 --- a/src/main/resources/static/js/search.js +++ b/src/main/resources/static/js/search.js @@ -43,7 +43,7 @@ document.querySelector('#navbarSearchInput').addEventListener('input', function( var titleElement = item.querySelector('.icon-text'); var iconElement = item.querySelector('.icon'); var itemHref = item.getAttribute('href'); - var tags = item.getAttribute('data-tags') || ""; // If no tags, default to empty string + var tags = item.getAttribute('data-bs-tags') || ""; // If no tags, default to empty string if (titleElement && iconElement && itemHref !== '#') { var title = titleElement.innerText; diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html index bd01c24ef..5a4882e52 100644 --- a/src/main/resources/templates/account.html +++ b/src/main/resources/templates/account.html @@ -1,4 +1,4 @@ - + @@ -24,15 +24,15 @@

    -
    +
    -
    +
    -
    +
    @@ -42,19 +42,19 @@

    Change Password?

    -
    +
    -
    +
    -
    +
    -
    +
    @@ -286,7 +286,7 @@ -
    +
    diff --git a/src/main/resources/templates/addUsers.html b/src/main/resources/templates/addUsers.html index fe37e71c0..c590988a9 100644 --- a/src/main/resources/templates/addUsers.html +++ b/src/main/resources/templates/addUsers.html @@ -41,15 +41,15 @@

    Add New User

    -
    +
    -
    +
    -
    +
    - +

    diff --git a/src/main/resources/templates/convert/img-to-pdf.html b/src/main/resources/templates/convert/img-to-pdf.html index 3182eb9d8..78da19341 100644 --- a/src/main/resources/templates/convert/img-to-pdf.html +++ b/src/main/resources/templates/convert/img-to-pdf.html @@ -23,13 +23,13 @@
    - +
    - +
    -
    +
    -
    +
    @@ -26,14 +26,14 @@
    -
    +
    -
    +
    -
    +
    diff --git a/src/main/resources/templates/convert/pdf-to-presentation.html b/src/main/resources/templates/convert/pdf-to-presentation.html index f5f73397f..4c7840170 100644 --- a/src/main/resources/templates/convert/pdf-to-presentation.html +++ b/src/main/resources/templates/convert/pdf-to-presentation.html @@ -15,7 +15,7 @@
    -
    +
    diff --git a/src/main/resources/templates/convert/pdf-to-word.html b/src/main/resources/templates/convert/pdf-to-word.html index c183d1bca..a10ca12f5 100644 --- a/src/main/resources/templates/convert/pdf-to-word.html +++ b/src/main/resources/templates/convert/pdf-to-word.html @@ -15,7 +15,7 @@
    -
    +
    -
    +
    diff --git a/src/main/resources/templates/fragments/card.html b/src/main/resources/templates/fragments/card.html index 48142b033..c3583da67 100644 --- a/src/main/resources/templates/fragments/card.html +++ b/src/main/resources/templates/fragments/card.html @@ -1,8 +1,8 @@ -
    +
    Icon -
    +

    diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index 74536458a..7c6b785da 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -32,10 +32,11 @@ - - - - + + + + + @@ -57,7 +58,7 @@ - + -
    -
    - - -
    -
    -
    +
    +
    + +
    +
    +
    + diff --git a/src/main/resources/templates/fragments/errorBanner.html b/src/main/resources/templates/fragments/errorBanner.html index 98fd9aeb0..1d2153ab8 100644 --- a/src/main/resources/templates/fragments/errorBanner.html +++ b/src/main/resources/templates/fragments/errorBanner.html @@ -24,7 +24,7 @@

    - diff --git a/src/main/resources/templates/fragments/errorBannerPerPage.html b/src/main/resources/templates/fragments/errorBannerPerPage.html index e13655130..ccc2f7b40 100644 --- a/src/main/resources/templates/fragments/errorBannerPerPage.html +++ b/src/main/resources/templates/fragments/errorBannerPerPage.html @@ -7,7 +7,7 @@ - @@ -29,7 +29,7 @@ Go to Homepage - Close + Close
    diff --git a/src/main/resources/templates/fragments/langAndDarkMode.html b/src/main/resources/templates/fragments/langAndDarkMode.html new file mode 100644 index 000000000..b587e88e1 --- /dev/null +++ b/src/main/resources/templates/fragments/langAndDarkMode.html @@ -0,0 +1,75 @@ + + + + + + + + + \ 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 c6dcadd5d..060ebaf04 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -18,13 +18,13 @@ - -
    @@ -137,7 +137,7 @@ -
    - - + - + + + + + + + +