Merge remote-tracking branch 'origin/main' into Frooodle/license

# Conflicts:
#	src/main/resources/templates/home.html
This commit is contained in:
a 2024-09-20 13:37:14 +01:00
commit 6ca14edaf1
47 changed files with 606 additions and 385 deletions

View File

@ -183,19 +183,19 @@ Stirling PDF currently supports 38!
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) | | English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) | | English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| French (Français) (fr_FR) | ![90%](https://geps.dev/progress/90) | | French (Français) (fr_FR) | ![90%](https://geps.dev/progress/90) |
| German (Deutsch) (de_DE) | ![98%](https://geps.dev/progress/98) | | German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
| Greek (Ελληνικά) (el_GR) | ![79%](https://geps.dev/progress/79) | | Greek (Ελληνικά) (el_GR) | ![79%](https://geps.dev/progress/79) |
| Hindi (हिंदी) (hi_IN) | ![76%](https://geps.dev/progress/76) | | Hindi (हिंदी) (hi_IN) | ![76%](https://geps.dev/progress/76) |
| Hungarian (Magyar) (hu_HU) | ![73%](https://geps.dev/progress/73) | | Hungarian (Magyar) (hu_HU) | ![73%](https://geps.dev/progress/73) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![74%](https://geps.dev/progress/74) | | Indonesia (Bahasa Indonesia) (id_ID) | ![74%](https://geps.dev/progress/74) |
| Irish (Gaeilge) (ga_IE) | ![95%](https://geps.dev/progress/95) | | Irish (Gaeilge) (ga_IE) | ![95%](https://geps.dev/progress/95) |
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) | | Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Japanese (日本語) (ja_JP) | ![89%](https://geps.dev/progress/89) | | Japanese (日本語) (ja_JP) | ![92%](https://geps.dev/progress/92) |
| Korean (한국어) (ko_KR) | ![81%](https://geps.dev/progress/81) | | Korean (한국어) (ko_KR) | ![81%](https://geps.dev/progress/81) |
| Norwegian (Norsk) (no_NB) | ![95%](https://geps.dev/progress/95) | | Norwegian (Norsk) (no_NB) | ![95%](https://geps.dev/progress/95) |
| Polish (Polski) (pl_PL) | ![89%](https://geps.dev/progress/89) | | Polish (Polski) (pl_PL) | ![89%](https://geps.dev/progress/89) |
| Portuguese (Português) (pt_PT) | ![76%](https://geps.dev/progress/76) | | Portuguese (Português) (pt_PT) | ![76%](https://geps.dev/progress/76) |
| Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) | | Portuguese Brazilian (Português) (pt_BR) | ![99%](https://geps.dev/progress/99) |
| Romanian (Română) (ro_RO) | ![97%](https://geps.dev/progress/97) | | Romanian (Română) (ro_RO) | ![97%](https://geps.dev/progress/97) |
| Russian (Русский) (ru_RU) | ![81%](https://geps.dev/progress/81) | | Russian (Русский) (ru_RU) | ![81%](https://geps.dev/progress/81) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![76%](https://geps.dev/progress/76) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![76%](https://geps.dev/progress/76) |

View File

@ -0,0 +1,10 @@
#!/bin/bash
translation_key="pdfToPDFA.credit"
old_value="OCRmyPDF"
new_value="ghostscript"
for file in ../src/main/resources/messages_*.properties; do
sed -i "/^$translation_key=/s/$old_value/$new_value/" "$file"
echo "Updated $file"
done

View File

@ -1,22 +1,15 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -29,7 +22,6 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest; import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;
@ -41,13 +33,6 @@ public class ConvertPDFToPDFA {
private static final Logger logger = LoggerFactory.getLogger(ConvertPDFToPDFA.class); private static final Logger logger = LoggerFactory.getLogger(ConvertPDFToPDFA.class);
private final CustomPDDocumentFactory pdfDocumentFactory;
@Autowired
public ConvertPDFToPDFA(CustomPDDocumentFactory pdfDocumentFactory) {
this.pdfDocumentFactory = pdfDocumentFactory;
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa") @PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@Operation( @Operation(
summary = "Convert a PDF to a PDF/A", summary = "Convert a PDF to a PDF/A",
@ -61,32 +46,7 @@ public class ConvertPDFToPDFA {
// Convert MultipartFile to byte[] // Convert MultipartFile to byte[]
byte[] pdfBytes = inputFile.getBytes(); byte[] pdfBytes = inputFile.getBytes();
// Load the PDF document // Save the uploaded file to a temporary location
PDDocument document = pdfDocumentFactory.load(pdfBytes);
// Get the document catalog
PDDocumentCatalog catalog = document.getDocumentCatalog();
// Get the AcroForm
PDAcroForm acroForm = catalog.getAcroForm();
if (acroForm != null) {
// Remove signature fields safely
List<PDField> fieldsToRemove =
acroForm.getFields().stream()
.filter(field -> field instanceof PDSignatureField)
.collect(Collectors.toList());
if (!fieldsToRemove.isEmpty()) {
acroForm.flatten(fieldsToRemove, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.save(baos);
pdfBytes = baos.toByteArray();
}
}
document.close();
// Save the uploaded (and possibly modified) file to a temporary location
Path tempInputFile = Files.createTempFile("input_", ".pdf"); Path tempInputFile = Files.createTempFile("input_", ".pdf");
try (OutputStream outputStream = new FileOutputStream(tempInputFile.toFile())) { try (OutputStream outputStream = new FileOutputStream(tempInputFile.toFile())) {
outputStream.write(pdfBytes); outputStream.write(pdfBytes);
@ -95,28 +55,37 @@ public class ConvertPDFToPDFA {
// Prepare the output file path // Prepare the output file path
Path tempOutputFile = Files.createTempFile("output_", ".pdf"); Path tempOutputFile = Files.createTempFile("output_", ".pdf");
// Prepare the OCRmyPDF command // Prepare the ghostscript command
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
command.add("ocrmypdf"); command.add("gs");
command.add("--skip-text"); command.add("-dPDFA=" + ("pdfa".equals(outputFormat) ? "2" : "1"));
command.add("--tesseract-timeout=0"); command.add("-dNOPAUSE");
command.add("--output-type"); command.add("-dBATCH");
command.add(outputFormat.toString()); command.add("-sColorConversionStrategy=UseDeviceIndependentColor");
command.add(tempInputFile.toString()); command.add("-sDEVICE=pdfwrite");
command.add("-dPDFACompatibilityPolicy=2");
command.add("-o");
command.add(tempOutputFile.toString()); command.add(tempOutputFile.toString());
command.add(tempInputFile.toString());
ProcessExecutorResult returnCode = ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF) ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT)
.runCommandWithOutputHandling(command); .runCommandWithOutputHandling(command);
if (returnCode.getRc() != 0) {
logger.info(
outputFormat + " conversion failed with return code: " + returnCode.getRc());
}
try { try {
PDDocument doc = pdfDocumentFactory.load(tempOutputFile.toFile()); byte[] pdfBytesOutput = Files.readAllBytes(tempOutputFile);
// Return the optimized PDF as a response // Return the optimized PDF as a response
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()) Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "") .replaceFirst("[.][^.]+$", "")
+ "_PDFA.pdf"; + "_PDFA.pdf";
return WebResponseUtils.pdfDocToWebResponse(doc, outputFilename); return WebResponseUtils.bytesToWebResponse(
pdfBytesOutput, outputFilename, MediaType.APPLICATION_PDF);
} finally { } finally {
// Clean up the temporary files // Clean up the temporary files
Files.deleteIfExists(tempInputFile); Files.deleteIfExists(tempInputFile);

View File

@ -90,22 +90,35 @@ public class ExtractImagesController {
// Iterate over each page // Iterate over each page
for (int pgNum = 0; pgNum < document.getPages().getCount(); pgNum++) { for (int pgNum = 0; pgNum < document.getPages().getCount(); pgNum++) {
PDPage page = document.getPage(pgNum); PDPage page = document.getPage(pgNum);
int pageNum = document.getPages().indexOf(page) + 1;
// Submit a task for processing each page
Future<Void> future = Future<Void> future =
executor.submit( executor.submit(
() -> { () -> {
extractImagesFromPage( // Use the page number directly from the iterator, so no need to
page, // calculate manually
format, int pageNum = document.getPages().indexOf(page) + 1;
filename,
pageNum, try {
processedImages, // Call the image extraction method for each page
zos, extractImagesFromPage(
allowDuplicates); page,
return null; format,
filename,
pageNum,
processedImages,
zos,
allowDuplicates);
} catch (IOException e) {
// Log the error and continue processing other pages
logger.error(
"Error extracting images from page {}: {}",
pageNum,
e.getMessage());
}
return null; // Callable requires a return type
}); });
// Add the Future object to the list to track completion
futures.add(future); futures.add(future);
} }

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=تغيير
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF إلى PDF/A pdfToPDFA.title=PDF إلى PDF/A
pdfToPDFA.header=PDF إلى PDF/A pdfToPDFA.header=PDF إلى PDF/A
pdfToPDFA.credit=تستخدم هذه الخدمة OCRmyPDF لتحويل PDF/A. pdfToPDFA.credit=تستخدم هذه الخدمة ghostscript لتحويل PDF/A.
pdfToPDFA.submit=تحويل pdfToPDFA.submit=تحويل
pdfToPDFA.tip=لا يعمل حاليًا لمدخلات متعددة في وقت واحد pdfToPDFA.tip=لا يعمل حاليًا لمدخلات متعددة في وقت واحد
pdfToPDFA.outputFormat=تنسيق الإخراج pdfToPDFA.outputFormat=تنسيق الإخراج

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Промени
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF към PDF/A pdfToPDFA.title=PDF към PDF/A
pdfToPDFA.header=PDF към PDF/A pdfToPDFA.header=PDF към PDF/A
pdfToPDFA.credit=Тази услуга използва OCRmyPDF за PDF/A преобразуване. pdfToPDFA.credit=Тази услуга използва ghostscript за PDF/A преобразуване.
pdfToPDFA.submit=Преобразуване pdfToPDFA.submit=Преобразуване
pdfToPDFA.tip=В момента не работи за няколко входа наведнъж pdfToPDFA.tip=В момента не работи за няколко входа наведнъж
pdfToPDFA.outputFormat=Изходен формат pdfToPDFA.outputFormat=Изходен формат

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Canvia
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF a PDF/A pdfToPDFA.title=PDF a PDF/A
pdfToPDFA.header=PDF a PDF/A pdfToPDFA.header=PDF a PDF/A
pdfToPDFA.credit=Utilitza OCRmyPDF per la conversió a PDF/A pdfToPDFA.credit=Utilitza ghostscript per la conversió a PDF/A
pdfToPDFA.submit=Converteix pdfToPDFA.submit=Converteix
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Změnit
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF na PDF/A pdfToPDFA.title=PDF na PDF/A
pdfToPDFA.header=PDF na PDF/A pdfToPDFA.header=PDF na PDF/A
pdfToPDFA.credit=Tato služba používá OCRmyPDF pro konverzi do formátu PDF/A pdfToPDFA.credit=Tato služba používá ghostscript pro konverzi do formátu PDF/A
pdfToPDFA.submit=Převést pdfToPDFA.submit=Převést
pdfToPDFA.tip=V současné době nepracuje pro více vstupů najednou pdfToPDFA.tip=V současné době nepracuje pro více vstupů najednou
pdfToPDFA.outputFormat=Výstupní formát pdfToPDFA.outputFormat=Výstupní formát

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Ændre
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF Til PDF/A pdfToPDFA.title=PDF Til PDF/A
pdfToPDFA.header=PDF Til PDF/A pdfToPDFA.header=PDF Til PDF/A
pdfToPDFA.credit=Denne tjeneste bruger OCRmyPDF til PDF/A-konvertering pdfToPDFA.credit=Denne tjeneste bruger ghostscript til PDF/A-konvertering
pdfToPDFA.submit=Konvertér pdfToPDFA.submit=Konvertér
pdfToPDFA.tip=Fungerer i øjeblikket ikke for flere input på én gang pdfToPDFA.tip=Fungerer i øjeblikket ikke for flere input på én gang
pdfToPDFA.outputFormat=Outputformat pdfToPDFA.outputFormat=Outputformat

View File

@ -77,10 +77,10 @@ color=Farbe
sponsor=Sponsor sponsor=Sponsor
info=Informationen info=Informationen
legal.privacy=Privacy Policy legal.privacy=Datenschutz
legal.terms=Terms and Conditions legal.terms=AGB
legal.accessibility=Accessibility legal.accessibility=Barrierefreiheit
legal.cookie=Cookie Policy legal.cookie=Cookie-Richtlinie
legal.impressum=Impressum legal.impressum=Impressum
############### ###############
@ -1023,7 +1023,7 @@ changeMetadata.submit=Ändern
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF zu PDF/A pdfToPDFA.title=PDF zu PDF/A
pdfToPDFA.header=PDF zu PDF/A pdfToPDFA.header=PDF zu PDF/A
pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung pdfToPDFA.credit=Dieser Dienst verwendet ghostscript für die PDF/A-Konvertierung
pdfToPDFA.submit=Konvertieren pdfToPDFA.submit=Konvertieren
pdfToPDFA.tip=Dieser Dienst kann nur einzelne Eingangsdateien verarbeiten. pdfToPDFA.tip=Dieser Dienst kann nur einzelne Eingangsdateien verarbeiten.
pdfToPDFA.outputFormat=Ausgabeformat pdfToPDFA.outputFormat=Ausgabeformat

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Αλλαγή
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF σε PDF/A pdfToPDFA.title=PDF σε PDF/A
pdfToPDFA.header=PDF σε PDF/A pdfToPDFA.header=PDF σε PDF/A
pdfToPDFA.credit=Αυτή η υπηρεσία χρησιμοποιεί OCRmyPDF για PDF/A μετατροπή pdfToPDFA.credit=Αυτή η υπηρεσία χρησιμοποιεί ghostscript για PDF/A μετατροπή
pdfToPDFA.submit=Μετατροπή pdfToPDFA.submit=Μετατροπή
pdfToPDFA.tip=Προς το παρόν δεν λειτουργεί για πολλαπλές εισόδους ταυτόχρονα pdfToPDFA.tip=Προς το παρόν δεν λειτουργεί για πολλαπλές εισόδους ταυτόχρονα
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1028,7 +1028,7 @@ changeMetadata.submit=Change
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF To PDF/A pdfToPDFA.title=PDF To PDF/A
pdfToPDFA.header=PDF To PDF/A pdfToPDFA.header=PDF To PDF/A
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion pdfToPDFA.credit=This service uses ghostscript for PDF/A conversion
pdfToPDFA.submit=Convert pdfToPDFA.submit=Convert
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Change
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF To PDF/A pdfToPDFA.title=PDF To PDF/A
pdfToPDFA.header=PDF To PDF/A pdfToPDFA.header=PDF To PDF/A
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion pdfToPDFA.credit=This service uses ghostscript for PDF/A conversion
pdfToPDFA.submit=Convert pdfToPDFA.submit=Convert
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Cambiar
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF a PDF/A pdfToPDFA.title=PDF a PDF/A
pdfToPDFA.header=PDF a PDF/A pdfToPDFA.header=PDF a PDF/A
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A pdfToPDFA.credit=Este servicio usa ghostscript para la conversión a PDF/A
pdfToPDFA.submit=Convertir pdfToPDFA.submit=Convertir
pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez
pdfToPDFA.outputFormat=Formato de salida pdfToPDFA.outputFormat=Formato de salida

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Aldatu
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDFa PDF/A bihurtu pdfToPDFA.title=PDFa PDF/A bihurtu
pdfToPDFA.header=PDFa PDF/A bihurtu pdfToPDFA.header=PDFa PDF/A bihurtu
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko pdfToPDFA.credit=Zerbitzu honek ghostscript erabiltzen du PDFak PDF/A bihurtzeko
pdfToPDFA.submit=Bihurtu pdfToPDFA.submit=Bihurtu
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Modifier
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF en PDF/A pdfToPDFA.title=PDF en PDF/A
pdfToPDFA.header=PDF en PDF/A pdfToPDFA.header=PDF en PDF/A
pdfToPDFA.credit=Ce service utilise OCRmyPDF pour la conversion en PDF/A. pdfToPDFA.credit=Ce service utilise ghostscript pour la conversion en PDF/A.
pdfToPDFA.submit=Convertir pdfToPDFA.submit=Convertir
pdfToPDFA.tip=Ne fonctionne actuellement pas pour plusieurs entrées à la fois pdfToPDFA.tip=Ne fonctionne actuellement pas pour plusieurs entrées à la fois
pdfToPDFA.outputFormat=Format de sortie pdfToPDFA.outputFormat=Format de sortie

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Athrú
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF Go PDF/A pdfToPDFA.title=PDF Go PDF/A
pdfToPDFA.header=PDF Go PDF/A pdfToPDFA.header=PDF Go PDF/A
pdfToPDFA.credit=Úsáideann an tseirbhís seo OCRmyPDF chun PDF/A a thiontú pdfToPDFA.credit=Úsáideann an tseirbhís seo ghostscript chun PDF/A a thiontú
pdfToPDFA.submit=Tiontaigh pdfToPDFA.submit=Tiontaigh
pdfToPDFA.tip=Faoi láthair ní oibríonn sé le haghaidh ionchuir iolracha ag an am céanna pdfToPDFA.tip=Faoi láthair ní oibríonn sé le haghaidh ionchuir iolracha ag an am céanna
pdfToPDFA.outputFormat=Formáid aschuir pdfToPDFA.outputFormat=Formáid aschuir

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=बदलें
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF से PDF/A में pdfToPDFA.title=PDF से PDF/A में
pdfToPDFA.header=PDF से PDF/A में pdfToPDFA.header=PDF से PDF/A में
pdfToPDFA.credit=इस सेवा में PDF/A परिवर्तन के लिए OCRmyPDF का उपयोग किया जाता है। pdfToPDFA.credit=इस सेवा में PDF/A परिवर्तन के लिए ghostscript का उपयोग किया जाता है।
pdfToPDFA.submit=परिवर्तित करें pdfToPDFA.submit=परिवर्तित करें
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Promijeniti
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF u PDF/A pdfToPDFA.title=PDF u PDF/A
pdfToPDFA.header=PDF u PDF/A pdfToPDFA.header=PDF u PDF/A
pdfToPDFA.credit=Ova usluga koristi OCRmyPDF za PDF/A pretvorbu pdfToPDFA.credit=Ova usluga koristi ghostscript za PDF/A pretvorbu
pdfToPDFA.submit=Pretvoriti pdfToPDFA.submit=Pretvoriti
pdfToPDFA.tip=Trenutno ne radi za više unosa odjednom pdfToPDFA.tip=Trenutno ne radi za više unosa odjednom
pdfToPDFA.outputFormat=Izlazni format pdfToPDFA.outputFormat=Izlazni format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Módosítás
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF >> PDF/A pdfToPDFA.title=PDF >> PDF/A
pdfToPDFA.header=PDF >> PDF/A pdfToPDFA.header=PDF >> PDF/A
pdfToPDFA.credit=Ez a szolgáltatás az OCRmyPDF-t használja a PDF/A konverzióhoz pdfToPDFA.credit=Ez a szolgáltatás az ghostscript-t használja a PDF/A konverzióhoz
pdfToPDFA.submit=Konvertálás pdfToPDFA.submit=Konvertálás
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Ganti
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF Ke PDF/A pdfToPDFA.title=PDF Ke PDF/A
pdfToPDFA.header=PDF ke PDF/A pdfToPDFA.header=PDF ke PDF/A
pdfToPDFA.credit=Layanan ini menggunakan OCRmyPDF untuk konversi PDF/A. pdfToPDFA.credit=Layanan ini menggunakan ghostscript untuk konversi PDF/A.
pdfToPDFA.submit=Konversi pdfToPDFA.submit=Konversi
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -81,7 +81,7 @@ legal.privacy=Informativa sulla privacy
legal.terms=Termini e Condizioni legal.terms=Termini e Condizioni
legal.accessibility=Accessibilità legal.accessibility=Accessibilità
legal.cookie=Informativa sui cookie legal.cookie=Informativa sui cookie
legal.impressum=Impressum legal.impressum=Informazioni legali
############### ###############
# Pipeline # # Pipeline #
@ -1023,7 +1023,7 @@ changeMetadata.submit=Cambia proprietà
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=Da PDF a PDF/A pdfToPDFA.title=Da PDF a PDF/A
pdfToPDFA.header=Da PDF a PDF/A pdfToPDFA.header=Da PDF a PDF/A
pdfToPDFA.credit=Questo servizio utilizza OCRmyPDF per la conversione in PDF/A. pdfToPDFA.credit=Questo servizio utilizza ghostscript per la conversione in PDF/A.
pdfToPDFA.submit=Converti pdfToPDFA.submit=Converti
pdfToPDFA.tip=Attualmente non funziona per più input contemporaneamente pdfToPDFA.tip=Attualmente non funziona per più input contemporaneamente
pdfToPDFA.outputFormat=Formato di output pdfToPDFA.outputFormat=Formato di output

View File

@ -3,8 +3,8 @@
########### ###########
# 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 language.direction=ltr
addPageNumbers.fontSize=Font Size addPageNumbers.fontSize=フォントサイズ
addPageNumbers.fontName=Font Name addPageNumbers.fontName=フォント名
pdfPrompt=PDFを選択 pdfPrompt=PDFを選択
multiPdfPrompt=PDFを選択 (2つ以上) multiPdfPrompt=PDFを選択 (2つ以上)
multiPdfDropPrompt=PDFを選択 (又はドラッグ&ドロップ) multiPdfDropPrompt=PDFを選択 (又はドラッグ&ドロップ)
@ -77,11 +77,11 @@ color=色
sponsor=スポンサー sponsor=スポンサー
info=Info info=Info
legal.privacy=Privacy Policy legal.privacy=プライバシーポリシー
legal.terms=Terms and Conditions legal.terms=利用規約
legal.accessibility=Accessibility legal.accessibility=アクセシビリティ
legal.cookie=Cookie Policy legal.cookie=Cookieポリシー
legal.impressum=Impressum legal.impressum=著作権利者情報
############### ###############
# Pipeline # # Pipeline #
@ -198,13 +198,13 @@ adminUserSettings.forceChange=ログイン時にユーザー名/パスワード
adminUserSettings.submit=ユーザーの保存 adminUserSettings.submit=ユーザーの保存
adminUserSettings.changeUserRole=ユーザーの役割を変更する adminUserSettings.changeUserRole=ユーザーの役割を変更する
adminUserSettings.authenticated=認証済 adminUserSettings.authenticated=認証済
adminUserSettings.editOwnProfil=Edit own profile adminUserSettings.editOwnProfil=プロフィールの編集
adminUserSettings.enabledUser=enabled user adminUserSettings.enabledUser=有効なユーザー
adminUserSettings.disabledUser=disabled user adminUserSettings.disabledUser=無効なユーザー
adminUserSettings.activeUsers=Active Users: adminUserSettings.activeUsers=アクティブユーザー:
adminUserSettings.disabledUsers=Disabled Users: adminUserSettings.disabledUsers=無効なユーザー:
adminUserSettings.totalUsers=Total Users: adminUserSettings.totalUsers=ユーザー合計:
adminUserSettings.lastRequest=Last Request adminUserSettings.lastRequest=最後のリクエスト
database.title=データベースのインポート/エクスポート database.title=データベースのインポート/エクスポート
@ -496,21 +496,21 @@ login.locked=あなたのアカウントはロックされています。
login.signinTitle=サインインしてください login.signinTitle=サインインしてください
login.ssoSignIn=シングルサインオンでログイン login.ssoSignIn=シングルサインオンでログイン
login.oauth2AutoCreateDisabled=OAuth 2自動作成ユーザーが無効 login.oauth2AutoCreateDisabled=OAuth 2自動作成ユーザーが無効
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oauth2AdminBlockedUser=現在、未登録ユーザーの登録またはログインはブロックされています。管理者にお問い合わせください。
login.oauth2RequestNotFound=認証リクエストが見つかりません login.oauth2RequestNotFound=認証リクエストが見つかりません
login.oauth2InvalidUserInfoResponse=無効なユーザー情報の応答 login.oauth2InvalidUserInfoResponse=無効なユーザー情報の応答
login.oauth2invalidRequest=無効なリクエスト login.oauth2invalidRequest=無効なリクエスト
login.oauth2AccessDenied=アクセス拒否 login.oauth2AccessDenied=アクセス拒否
login.oauth2InvalidTokenResponse=無効なトークン応答 login.oauth2InvalidTokenResponse=無効なトークン応答
login.oauth2InvalidIdToken=無効なIDトークン login.oauth2InvalidIdToken=無効なIDトークン
login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. login.userIsDisabled=ユーザーは非アクティブ化されており、現在このユーザー名でのログインはブロックされています。管理者に連絡してください。
#auto-redact #auto-redact
autoRedact.title=自動塗りつぶし autoRedact.title=自動塗りつぶし
autoRedact.header=自動塗りつぶし autoRedact.header=自動塗りつぶし
autoRedact.colorLabel=カラー autoRedact.colorLabel=カラー
autoRedact.textsToRedactLabel=編集するテキスト (line-separated) autoRedact.textsToRedactLabel=編集するテキスト(行区切り)
autoRedact.textsToRedactPlaceholder=例 \n機密 \n極秘 autoRedact.textsToRedactPlaceholder=例 \n機密 \n極秘
autoRedact.useRegexLabel=正規表現を使用する autoRedact.useRegexLabel=正規表現を使用する
autoRedact.wholeWordSearchLabel=単語単位の検索 autoRedact.wholeWordSearchLabel=単語単位の検索
@ -679,7 +679,7 @@ pageLayout.submit=送信
scalePages.title=ページの縮尺の調整 scalePages.title=ページの縮尺の調整
scalePages.header=ページの縮尺の調整 scalePages.header=ページの縮尺の調整
scalePages.pageSize=1ページのサイズ scalePages.pageSize=1ページのサイズ
scalePages.keepPageSize=Original Size scalePages.keepPageSize=元のサイズ
scalePages.scaleFactor=1ページの拡大レベル (トリミング)。 scalePages.scaleFactor=1ページの拡大レベル (トリミング)。
scalePages.submit=送信 scalePages.submit=送信
@ -728,8 +728,8 @@ removeAnnotations.submit=削除
#compare #compare
compare.title=比較 compare.title=比較
compare.header=PDFの比較 compare.header=PDFの比較
compare.highlightColor.1=Highlight Color 1: compare.highlightColor.1=ハイライトカラー 1:
compare.highlightColor.2=Highlight Color 2: compare.highlightColor.2=ハイライトカラー 2:
compare.document.1=ドキュメント 1 compare.document.1=ドキュメント 1
compare.document.2=ドキュメント 2 compare.document.2=ドキュメント 2
compare.submit=比較 compare.submit=比較
@ -781,7 +781,7 @@ ScannerImageSplit.selectText.7=最小輪郭面積:
ScannerImageSplit.selectText.8=画像の最小の輪郭面積のしきい値を設定。 ScannerImageSplit.selectText.8=画像の最小の輪郭面積のしきい値を設定。
ScannerImageSplit.selectText.9=境界線サイズ: ScannerImageSplit.selectText.9=境界線サイズ:
ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。 ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。
ScannerImageSplit.info=Python is not installed. It is required to run. ScannerImageSplit.info=Pythonがインストールされていません。実行する必要があります。
#OCR #OCR
@ -808,7 +808,7 @@ ocr.submit=OCRでPDFを処理する
extractImages.title=画像の抽出 extractImages.title=画像の抽出
extractImages.header=画像の抽出 extractImages.header=画像の抽出
extractImages.selectText=抽出した画像のフォーマットを選択 extractImages.selectText=抽出した画像のフォーマットを選択
extractImages.allowDuplicates=Save duplicate images extractImages.allowDuplicates=重複した画像を保存する
extractImages.submit=抽出 extractImages.submit=抽出
@ -864,7 +864,7 @@ pdfOrganiser.mode.6=奇数-偶数分割
pdfOrganiser.mode.7=最初に削除 pdfOrganiser.mode.7=最初に削除
pdfOrganiser.mode.8=最後を削除 pdfOrganiser.mode.8=最後を削除
pdfOrganiser.mode.9=最初と最後を削除 pdfOrganiser.mode.9=最初と最後を削除
pdfOrganiser.mode.10=Odd-Even Merge pdfOrganiser.mode.10=奇数-偶数の結合
pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1) pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1)
@ -933,7 +933,7 @@ pdfToImage.color=カラー
pdfToImage.grey=グレースケール pdfToImage.grey=グレースケール
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!) pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
pdfToImage.submit=変換 pdfToImage.submit=変換
pdfToImage.info=Python is not installed. Required for WebP conversion. pdfToImage.info=Pythonがインストールされていません。WebPの変換に必要です。
#addPassword #addPassword
@ -970,7 +970,7 @@ watermark.selectText.6=高さスペース (各透かし間の垂直方向のス
watermark.selectText.7=不透明度 (0% - 100%): watermark.selectText.7=不透明度 (0% - 100%):
watermark.selectText.8=透かしの種類: watermark.selectText.8=透かしの種類:
watermark.selectText.9=透かしの画像: watermark.selectText.9=透かしの画像:
watermark.selectText.10=Convert PDF to PDF-Image watermark.selectText.10=PDFをPDFイメージに変換する
watermark.submit=透かしを追加 watermark.submit=透かしを追加
watermark.type.1=テキスト watermark.type.1=テキスト
watermark.type.2=画像 watermark.type.2=画像
@ -1023,7 +1023,7 @@ changeMetadata.submit=変更
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDFをPDF/Aに変換 pdfToPDFA.title=PDFをPDF/Aに変換
pdfToPDFA.header=PDFをPDF/Aに変換 pdfToPDFA.header=PDFをPDF/Aに変換
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。 pdfToPDFA.credit=本サービスはPDF/Aの変換にghostscriptを使用しています。
pdfToPDFA.submit=変換 pdfToPDFA.submit=変換
pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=변경
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF를 PDF/A로 pdfToPDFA.title=PDF를 PDF/A로
pdfToPDFA.header=PDF 문서를 PDF/A로 변환 pdfToPDFA.header=PDF 문서를 PDF/A로 변환
pdfToPDFA.credit=이 서비스는 PDF/A 변환을 위해 OCRmyPDF 문서를 사용합니다. pdfToPDFA.credit=이 서비스는 PDF/A 변환을 위해 ghostscript 문서를 사용합니다.
pdfToPDFA.submit=변환 pdfToPDFA.submit=변환
pdfToPDFA.tip=현재 한 번에 여러 입력에 대해 작동하지 않습니다. pdfToPDFA.tip=현재 한 번에 여러 입력에 대해 작동하지 않습니다.
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Wijzigen
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF naar PDF/A pdfToPDFA.title=PDF naar PDF/A
pdfToPDFA.header=PDF naar PDF/A pdfToPDFA.header=PDF naar PDF/A
pdfToPDFA.credit=Deze service gebruikt OCRmyPDF voor PDF/A-conversie pdfToPDFA.credit=Deze service gebruikt ghostscript voor PDF/A-conversie
pdfToPDFA.submit=Converteren pdfToPDFA.submit=Converteren
pdfToPDFA.tip=Werkt momenteel niet voor meerdere inputs tegelijkertijd. pdfToPDFA.tip=Werkt momenteel niet voor meerdere inputs tegelijkertijd.
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Endre
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF til PDF/A pdfToPDFA.title=PDF til PDF/A
pdfToPDFA.header=PDF til PDF/A pdfToPDFA.header=PDF til PDF/A
pdfToPDFA.credit=Denne tjenesten bruker OCRmyPDF for PDF/A-konvertering pdfToPDFA.credit=Denne tjenesten bruker ghostscript for PDF/A-konvertering
pdfToPDFA.submit=Konverter pdfToPDFA.submit=Konverter
pdfToPDFA.tip=Fungere for øyeblikket ikke for flere innganger samtidig pdfToPDFA.tip=Fungere for øyeblikket ikke for flere innganger samtidig
pdfToPDFA.outputFormat=Utdataformat pdfToPDFA.outputFormat=Utdataformat

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Zmień
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF na PDF/A pdfToPDFA.title=PDF na PDF/A
pdfToPDFA.header=PDF na PDF/A pdfToPDFA.header=PDF na PDF/A
pdfToPDFA.credit=Ta usługa używa OCRmyPDF do konwersji PDF/A pdfToPDFA.credit=Ta usługa używa ghostscript do konwersji PDF/A
pdfToPDFA.submit=Konwertuj pdfToPDFA.submit=Konwertuj
pdfToPDFA.tip=Tylko jeden plik na raz pdfToPDFA.tip=Tylko jeden plik na raz
pdfToPDFA.outputFormat=Format wyjściowy: pdfToPDFA.outputFormat=Format wyjściowy:

View File

@ -3,8 +3,8 @@
########### ###########
# 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 language.direction=ltr
addPageNumbers.fontSize=Font Size addPageNumbers.fontSize=Tamanho da fonte
addPageNumbers.fontName=Font Name addPageNumbers.fontName=Nome da fonte
pdfPrompt=Selecione PDF(s) pdfPrompt=Selecione PDF(s)
multiPdfPrompt=Selecione PDFs (2+) multiPdfPrompt=Selecione PDFs (2+)
multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs necessários multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs necessários
@ -77,11 +77,11 @@ color=Cor
sponsor=Patrocine sponsor=Patrocine
info=Informações info=Informações
legal.privacy=Privacy Policy legal.privacy=Política de Privacidade
legal.terms=Terms and Conditions legal.terms=Termos e Condições
legal.accessibility=Accessibility legal.accessibility=Acessibilidade
legal.cookie=Cookie Policy legal.cookie=Política de Cookies
legal.impressum=Impressum legal.impressum=Informações legais
############### ###############
# Pipeline # # Pipeline #
@ -507,12 +507,12 @@ login.userIsDisabled=O usuário está desativado, o login está atualmente bloqu
#auto-redact #auto-redact
autoRedact.title=Auto ocultar autoRedact.title=Redigir automaticamente
autoRedact.header=Auto ocultar autoRedact.header=Redigir automaticamente
autoRedact.colorLabel=Cor autoRedact.colorLabel=Cor
autoRedact.textsToRedactLabel=Text para ocultar (separado por linha) autoRedact.textsToRedactLabel=Texto para redigir (separado por linha)
autoRedact.textsToRedactPlaceholder=por exemplo: \nConfidencial \nSecreto autoRedact.textsToRedactPlaceholder=por exemplo: \nConfidencial \nSecreto
autoRedact.useRegexLabel=Usar Regex (Regular Expressions) autoRedact.useRegexLabel=Usar Regex (expressão regular)
autoRedact.wholeWordSearchLabel=Pesquisa de palavras inteiras autoRedact.wholeWordSearchLabel=Pesquisa de palavras inteiras
autoRedact.customPaddingLabel=Preenchimento extra personalizado autoRedact.customPaddingLabel=Preenchimento extra personalizado
autoRedact.convertPDFToImageLabel=Converter PDF em imagem PDF (Usado para remover o texto atrás da caixa) autoRedact.convertPDFToImageLabel=Converter PDF em imagem PDF (Usado para remover o texto atrás da caixa)
@ -679,7 +679,7 @@ pageLayout.submit=Enviar
scalePages.title=Ajustar Tamanho/Escala da Página scalePages.title=Ajustar Tamanho/Escala da Página
scalePages.header=Ajustar Tamanho/Escala da Página scalePages.header=Ajustar Tamanho/Escala da Página
scalePages.pageSize=Tamanho de uma página do documento. scalePages.pageSize=Tamanho de uma página do documento.
scalePages.keepPageSize=Original Size scalePages.keepPageSize=Tamanho original
scalePages.scaleFactor=Fator de zoom (corte) de uma página. scalePages.scaleFactor=Fator de zoom (corte) de uma página.
scalePages.submit=Enviar scalePages.submit=Enviar
@ -781,7 +781,7 @@ ScannerImageSplit.selectText.7=Área mínima de contorno:
ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto
ScannerImageSplit.selectText.9=Tamanho da borda: ScannerImageSplit.selectText.9=Tamanho da borda:
ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida para evitar bordas brancas na saída (padrão: 1). ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida para evitar bordas brancas na saída (padrão: 1).
ScannerImageSplit.info=Python is not installed. It is required to run. ScannerImageSplit.info=Python não está instalado. É necessário para executar.
#OCR #OCR
@ -808,7 +808,7 @@ ocr.submit=Processar PDF com OCR
extractImages.title=Extrair imagens extractImages.title=Extrair imagens
extractImages.header=Extrair imagens extractImages.header=Extrair imagens
extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas
extractImages.allowDuplicates=Save duplicate images extractImages.allowDuplicates=Salvar imagens duplicadas
extractImages.submit=Extrair extractImages.submit=Extrair
@ -933,7 +933,7 @@ pdfToImage.color=Colorida
pdfToImage.grey=Escala de Cinza pdfToImage.grey=Escala de Cinza
pdfToImage.blackwhite=Preto e Branco (pode perder de dados!) pdfToImage.blackwhite=Preto e Branco (pode perder de dados!)
pdfToImage.submit=Converter pdfToImage.submit=Converter
pdfToImage.info=Python is not installed. Required for WebP conversion. pdfToImage.info=Python não está instalado. Necessário para conversão WebP.
#addPassword #addPassword
@ -1023,7 +1023,7 @@ changeMetadata.submit=Alterar
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF para PDF/A pdfToPDFA.title=PDF para PDF/A
pdfToPDFA.header=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 ghostscript para conversão de PDF/A
pdfToPDFA.submit=Converter pdfToPDFA.submit=Converter
pdfToPDFA.tip=Atualmente não funciona para múltiplas entradas ao mesmo tempo pdfToPDFA.tip=Atualmente não funciona para múltiplas entradas ao mesmo tempo
pdfToPDFA.outputFormat=Formato de saída pdfToPDFA.outputFormat=Formato de saída

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Mudar
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF para PDF/A pdfToPDFA.title=PDF para PDF/A
pdfToPDFA.header=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 ghostscript para Conversão de PDF/A
pdfToPDFA.submit=Converter pdfToPDFA.submit=Converter
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Schimbă
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF către PDF/A pdfToPDFA.title=PDF către PDF/A
pdfToPDFA.header=PDF către PDF/A pdfToPDFA.header=PDF către PDF/A
pdfToPDFA.credit=Acest serviciu utilizează OCRmyPDF pentru conversia în PDF/A pdfToPDFA.credit=Acest serviciu utilizează ghostscript pentru conversia în PDF/A
pdfToPDFA.submit=Convertește pdfToPDFA.submit=Convertește
pdfToPDFA.tip=În prezent nu funcționează pentru mai multe intrări simultan pdfToPDFA.tip=În prezent nu funcționează pentru mai multe intrări simultan
pdfToPDFA.outputFormat=Format de ieșire pdfToPDFA.outputFormat=Format de ieșire

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Изменить
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF в PDF/A pdfToPDFA.title=PDF в PDF/A
pdfToPDFA.header=PDF в PDF/A pdfToPDFA.header=PDF в PDF/A
pdfToPDFA.credit=Этот сервис использует OCRmyPDF для преобразования PDF/A pdfToPDFA.credit=Этот сервис использует ghostscript для преобразования PDF/A
pdfToPDFA.submit=Конвертировать pdfToPDFA.submit=Конвертировать
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Zmeniť
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF na PDF/A pdfToPDFA.title=PDF na PDF/A
pdfToPDFA.header=PDF na PDF/A pdfToPDFA.header=PDF na PDF/A
pdfToPDFA.credit=Táto služba používa OCRmyPDF na konverziu PDF/A pdfToPDFA.credit=Táto služba používa ghostscript na konverziu PDF/A
pdfToPDFA.submit=Konvertovať pdfToPDFA.submit=Konvertovať
pdfToPDFA.tip=Momentálne nefunguje pre viacero vstupov naraz pdfToPDFA.tip=Momentálne nefunguje pre viacero vstupov naraz
pdfToPDFA.outputFormat=Výstupný formát pdfToPDFA.outputFormat=Výstupný formát

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Promeni
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF u PDF/A pdfToPDFA.title=PDF u PDF/A
pdfToPDFA.header=PDF u PDF/A pdfToPDFA.header=PDF u PDF/A
pdfToPDFA.credit=Ova usluga koristi OCRmyPDF za konverziju u PDF/A format pdfToPDFA.credit=Ova usluga koristi ghostscript za konverziju u PDF/A format
pdfToPDFA.submit=Konvertuj pdfToPDFA.submit=Konvertuj
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Ändra
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF till PDF/A pdfToPDFA.title=PDF till PDF/A
pdfToPDFA.header=PDF till PDF/A pdfToPDFA.header=PDF till PDF/A
pdfToPDFA.credit=Denna tjänst använder OCRmyPDF för PDF/A-konvertering pdfToPDFA.credit=Denna tjänst använder ghostscript för PDF/A-konvertering
pdfToPDFA.submit=Konvertera pdfToPDFA.submit=Konvertera
pdfToPDFA.tip=Fungerar för närvarande inte för flera inmatningar samtidigt pdfToPDFA.tip=Fungerar för närvarande inte för flera inmatningar samtidigt
pdfToPDFA.outputFormat=Utdataformat pdfToPDFA.outputFormat=Utdataformat

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=เปลี่ยน
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF เป็น PDF/A pdfToPDFA.title=PDF เป็น PDF/A
pdfToPDFA.header=PDF เป็น PDF/A pdfToPDFA.header=PDF เป็น PDF/A
pdfToPDFA.credit=บริการนี้ใช้ OCRmyPDF สำหรับการแปลง PDF/A pdfToPDFA.credit=บริการนี้ใช้ ghostscript สำหรับการแปลง PDF/A
pdfToPDFA.submit=แปลง pdfToPDFA.submit=แปลง
pdfToPDFA.tip=ปัจจุบันไม่ทำงานสำหรับการป้อนข้อมูลหลายรายการพร้อมกัน pdfToPDFA.tip=ปัจจุบันไม่ทำงานสำหรับการป้อนข้อมูลหลายรายการพร้อมกัน
pdfToPDFA.outputFormat=รูปแบบผลลัพธ์ pdfToPDFA.outputFormat=รูปแบบผลลัพธ์

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Değiştir
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF'den PDF/A'ya pdfToPDFA.title=PDF'den PDF/A'ya
pdfToPDFA.header=PDF'den PDF/A'ya pdfToPDFA.header=PDF'den PDF/A'ya
pdfToPDFA.credit=Bu hizmet PDF/A dönüşümü için OCRmyPDF kullanır pdfToPDFA.credit=Bu hizmet PDF/A dönüşümü için ghostscript kullanır
pdfToPDFA.submit=Dönüştür pdfToPDFA.submit=Dönüştür
pdfToPDFA.tip=Şu anda aynı anda birden fazla giriş için çalışmıyor pdfToPDFA.tip=Şu anda aynı anda birden fazla giriş için çalışmıyor
pdfToPDFA.outputFormat=Çıkış formatı pdfToPDFA.outputFormat=Çıkış formatı

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Змінити
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF в PDF/A pdfToPDFA.title=PDF в PDF/A
pdfToPDFA.header=PDF в PDF/A pdfToPDFA.header=PDF в PDF/A
pdfToPDFA.credit=Цей сервіс використовує OCRmyPDF для перетворення у формат PDF/A pdfToPDFA.credit=Цей сервіс використовує ghostscript для перетворення у формат PDF/A
pdfToPDFA.submit=Конвертувати pdfToPDFA.submit=Конвертувати
pdfToPDFA.tip=Наразі не працює для кількох вхідних файлів одночасно pdfToPDFA.tip=Наразі не працює для кількох вхідних файлів одночасно
pdfToPDFA.outputFormat=Вихідний формат pdfToPDFA.outputFormat=Вихідний формат

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=Thay đổi
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF sang PDF/A pdfToPDFA.title=PDF sang PDF/A
pdfToPDFA.header=PDF sang PDF/A pdfToPDFA.header=PDF sang PDF/A
pdfToPDFA.credit=Dịch vụ này sử dụng OCRmyPDF để chuyển đổi PDF/A pdfToPDFA.credit=Dịch vụ này sử dụng ghostscript để chuyển đổi PDF/A
pdfToPDFA.submit=Chuyển đổi pdfToPDFA.submit=Chuyển đổi
pdfToPDFA.tip=Hiện tại không hoạt động với nhiều đầu vào cùng lúc pdfToPDFA.tip=Hiện tại không hoạt động với nhiều đầu vào cùng lúc
pdfToPDFA.outputFormat=Định dạng đầu ra pdfToPDFA.outputFormat=Định dạng đầu ra

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=更改
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF转PDF/A pdfToPDFA.title=PDF转PDF/A
pdfToPDFA.header=将PDF转换为PDF/A pdfToPDFA.header=将PDF转换为PDF/A
pdfToPDFA.credit=此服务使用OCRmyPDF进行PDF/A转换 pdfToPDFA.credit=此服务使用ghostscript进行PDF/A转换
pdfToPDFA.submit=转换 pdfToPDFA.submit=转换
pdfToPDFA.tip=目前不支持上传多个 pdfToPDFA.tip=目前不支持上传多个
pdfToPDFA.outputFormat=输出格式 pdfToPDFA.outputFormat=输出格式

View File

@ -1023,7 +1023,7 @@ changeMetadata.submit=變更
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF 轉 PDF/A pdfToPDFA.title=PDF 轉 PDF/A
pdfToPDFA.header=PDF 轉 PDF/A pdfToPDFA.header=PDF 轉 PDF/A
pdfToPDFA.credit=此服務使用 OCRmyPDF 進行 PDF/A 轉換 pdfToPDFA.credit=此服務使用 ghostscript 進行 PDF/A 轉換
pdfToPDFA.submit=轉換 pdfToPDFA.submit=轉換
pdfToPDFA.tip=目前不支援上傳多個 pdfToPDFA.tip=目前不支援上傳多個
pdfToPDFA.outputFormat=輸出格式 pdfToPDFA.outputFormat=輸出格式

View File

@ -10,6 +10,26 @@
outline-color: var(--md-sys-color-outline-variant); outline-color: var(--md-sys-color-outline-variant);
} }
#filtersContainer {
display: flex;
width: 100%;
align-items: center;
justify-content: center;
gap: 10px;
}
.filter-button {
color: var(--md-sys-color-secondary);
user-select: none;
cursor: pointer;
transition: transform 0.3s;
transform-origin: center center;
}
.filter-button:hover {
transform: scale(1.08);
}
.search-icon { .search-icon {
position: absolute; position: absolute;
margin: 0.75rem 1rem; margin: 0.75rem 1rem;
@ -17,9 +37,50 @@
} }
.features-container { .features-container {
display: flex;
flex-direction: column;
gap: 30px;
}
.feature-group {
display: flex;
flex-direction: column;
}
.feature-group-header {
display: flex;
align-items: center;
justify-content: flex-start;
color: var(--md-sys-color-on-surface);
margin-bottom: 15px;
user-select: none;
cursor: pointer;
gap: 10px;
}
.feature-group-container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr)); grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr));
gap: 30px 30px; gap: 30px 30px;
transition: 0.5s all;
overflow: hidden;
margin: -20px;
padding: 20px;
}
.feature-group.collapsed>.feature-group-container {
max-height: 0 !important;
margin: 0;
padding: 0;
}
.header-expand-button {
transition: 0.5s all;
transform: rotate(90deg);
}
.header-expand-button.collapsed {
transform: rotate(0deg);
} }
.feature-card { .feature-card {
@ -151,5 +212,5 @@
} }
.hidden { .hidden {
visibility: hidden; visibility: hidden;
} }

View File

@ -136,7 +136,7 @@ span.icon-text::after {
/* Dropdown Scrollbar*/ /* Dropdown Scrollbar*/
.scrollable-y { .scrollable-y {
overflow-y: scroll; overflow-y: scroll;
height: 360px; height: 190px;
} }
.scrollable-y::-webkit-scrollbar { .scrollable-y::-webkit-scrollbar {

View File

@ -22,6 +22,26 @@ function filterCards() {
} }
} }
function updateFavoritesSection() {
const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container");
favoritesContainer.innerHTML = "";
const cards = Array.from(document.querySelectorAll(".feature-card"));
let favoritesAmount = 0;
cards.forEach(card => {
if (localStorage.getItem(card.id) === "favorite") {
const duplicate = card.cloneNode(true);
favoritesContainer.appendChild(duplicate);
favoritesAmount++;
}
});
if (favoritesAmount === 0) {
document.getElementById("groupFavorites").style.display = "none";
} else {
document.getElementById("groupFavorites").style.display = "flex";
};
reorderCards(favoritesContainer);
};
function toggleFavorite(element) { function toggleFavorite(element) {
var span = element.querySelector("span.material-symbols-rounded"); var span = element.querySelector("span.material-symbols-rounded");
var card = element.closest(".feature-card"); var card = element.closest(".feature-card");
@ -37,15 +57,17 @@ function toggleFavorite(element) {
card.classList.remove("favorite"); card.classList.remove("favorite");
localStorage.removeItem(cardId); localStorage.removeItem(cardId);
} }
reorderCards(); reorderCards(card.parentNode);
updateFavoritesSection();
updateFavoritesDropdown(); updateFavoritesDropdown();
filterCards(); filterCards();
} }
function reorderCards(container) {
function reorderCards() { var cards = Array.from(container.querySelectorAll(".feature-card"));
var container = document.querySelector(".features-container"); cards.forEach(function (card) {
var cards = Array.from(container.getElementsByClassName("feature-card")); container.removeChild(card);
});
cards.sort(function (a, b) { cards.sort(function (a, b) {
var aIsFavorite = localStorage.getItem(a.id) === "favorite"; var aIsFavorite = localStorage.getItem(a.id) === "favorite";
var bIsFavorite = localStorage.getItem(b.id) === "favorite"; var bIsFavorite = localStorage.getItem(b.id) === "favorite";
@ -55,19 +77,29 @@ function reorderCards() {
if (b.id === "update-link") { if (b.id === "update-link") {
return 1; return 1;
} }
if (aIsFavorite && !bIsFavorite) { if (aIsFavorite && !bIsFavorite) {
return -1; return -1;
} }
if (!aIsFavorite && bIsFavorite) { else if (!aIsFavorite && bIsFavorite) {
return 1; return 1;
} }
return 0; else {
return a.id > b.id;
}
}); });
cards.forEach(function (card) { cards.forEach(function (card) {
container.appendChild(card); container.appendChild(card);
}); });
} }
function reorderAllCards() {
const containers = Array.from(document.querySelectorAll(".feature-group-container"));
containers.forEach(function (container) {
reorderCards(container);
})
}
function initializeCards() { function initializeCards() {
var cards = document.querySelectorAll(".feature-card"); var cards = document.querySelectorAll(".feature-card");
cards.forEach(function (card) { cards.forEach(function (card) {
@ -79,21 +111,107 @@ function initializeCards() {
card.classList.add("favorite"); card.classList.add("favorite");
} }
}); });
reorderCards(); reorderAllCards();
updateFavoritesSection();
updateFavoritesDropdown(); updateFavoritesDropdown();
filterCards(); filterCards();
} }
function showFavoritesOnly() {
const groups = Array.from(document.querySelectorAll(".feature-group"));
if (localStorage.getItem("favoritesOnly") === "true") {
groups.forEach((group) => {
if (group.id !== "groupFavorites") {
group.style.display = "none";
};
})
} else {
groups.forEach((group) => {
if (group.id !== "groupFavorites") {
group.style.display = "flex";
};
})
};
}
function toggleFavoritesOnly() {
if (localStorage.getItem("favoritesOnly") === "true") {
localStorage.setItem("favoritesOnly", "false");
} else {
localStorage.setItem("favoritesOnly", "true");
}
showFavoritesOnly();
}
// Expands a feature group on true, collapses it on false and toggles state on null.
function expandCollapseToggle(group, expand = null) {
if (expand === null) {
group.classList.toggle("collapsed");
group.querySelector(".header-expand-button").classList.toggle("collapsed");
} else if (expand) {
group.classList.remove("collapsed");
group.querySelector(".header-expand-button").classList.remove("collapsed");
} else {
group.classList.add("collapsed");
group.querySelector(".header-expand-button").classList.add("collapsed");
}
const collapsed = localStorage.getItem("collapsedGroups") ? JSON.parse(localStorage.getItem("collapsedGroups")) : [];
const groupIndex = collapsed.indexOf(group.id);
if (group.classList.contains("collapsed")) {
if (groupIndex === -1) {
collapsed.push(group.id);
}
} else {
if (groupIndex !== -1) {
collapsed.splice(groupIndex, 1);
}
}
localStorage.setItem("collapsedGroups", JSON.stringify(collapsed));
}
function expandCollapseAll(expandAll) {
const groups = Array.from(document.querySelectorAll(".feature-group"));
groups.forEach((group) => {
expandCollapseToggle(group, expandAll);
})
}
window.onload = initializeCards; window.onload = initializeCards;
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
const materialIcons = new FontFaceObserver('Material Symbols Rounded'); const materialIcons = new FontFaceObserver('Material Symbols Rounded');
materialIcons.load().then(() => { materialIcons.load().then(() => {
document.querySelectorAll('.feature-card.hidden').forEach(el => { document.querySelectorAll('.feature-card.hidden').forEach(el => {
el.classList.remove('hidden'); el.classList.remove('hidden');
});
}).catch(() => {
console.error('Material Symbols Rounded font failed to load.');
}); });
}).catch(() => {
console.error('Material Symbols Rounded font failed to load.');
}); });
Array.from(document.querySelectorAll(".feature-group-header")).forEach(header => {
const parent = header.parentNode;
const container = header.parentNode.querySelector(".feature-group-container");
if (parent.id !== "groupFavorites") {
container.style.maxHeight = container.clientHeight + "px";
} else {
container.style.maxHeight = "500px";
}
header.onclick = () => {
expandCollapseToggle(parent);
};
})
const collapsed = localStorage.getItem("collapsedGroups") ? JSON.parse(localStorage.getItem("collapsedGroups")) : [];
Array.from(document.querySelectorAll(".feature-group")).forEach(group => {
if (collapsed.indexOf(group.id) !== -1) {
expandCollapseToggle(group, false);
}
})
showFavoritesOnly();
});

View File

@ -29,6 +29,7 @@ class ImageHighlighter {
imageClickEvent.stopPropagation(); imageClickEvent.stopPropagation();
}; };
bigImg.src = highlightEvent.target.src; bigImg.src = highlightEvent.target.src;
bigImg.style.rotate = highlightEvent.target.style.rotate;
this.imageHighlighter.appendChild(bigImg); this.imageHighlighter.appendChild(bigImg);
} }

View File

@ -0,0 +1,6 @@
<div th:fragment="featureGroupHeader" class="feature-group-header">
<h3 class="menu-title" th:text="${groupTitle}"></h3>
<span class="material-symbols-rounded header-expand-button">
chevron_right
</span>
</div>

View File

@ -7,11 +7,9 @@
</head> </head>
<body> <body>
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<!-- Jumbotron --> <!-- Jumbotron -->
<div class="p-5 rounded d-none d-md-block" id="jumbotron"> <div class="p-5 rounded d-none d-md-block" id="jumbotron">
<div class="container"> <div class="container">
@ -30,9 +28,26 @@
search search
</span> </span>
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus> <input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus>
<div id="filtersContainer">
<span class="material-symbols-rounded filter-button" onclick="toggleFavoritesOnly()">
star
</span>
<span class="material-symbols-rounded filter-button" onclick="expandCollapseAll(true)">
expand_all
</span>
<span class="material-symbols-rounded filter-button" onclick="expandCollapseAll(false)">
collapse_all
</span>
<span class="material-symbols-rounded filter-button hidden" onclick="switchViewMode()">
dashboard
</span>
</div>
<div class="features-container"> <div class="features-container">
<div th:if="${@shouldShow}" class="feature-card favorite update-notice" id="update-link" style="display: none;"> <div th:if="${@shouldShow}" class="feature-card favorite update-notice" id="update-link"
style="display: none;">
<a href="https://github.com/Stirling-Tools/Stirling-PDF/releases" target="_blank" rel="noopener"> <a href="https://github.com/Stirling-Tools/Stirling-PDF/releases" target="_blank" rel="noopener">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<div id="tool-icon" class="advance" alt="icon"> <div id="tool-icon" class="advance" alt="icon">
@ -46,196 +61,235 @@
</a> </a>
</div> </div>
<div <div id="groupFavorites" class="feature-group">
th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', toolIcon='family_history', tags=#{pipeline.tags}, toolGroup='advance')}"> <div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.favorite})}">
</div> </div>
<div <div class="feature-group-container">
th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', toolIcon='menu_book', tags=#{viewPdf.tags}, toolGroup='other')}"> </div>
</div>
<div
th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', toolIcon='construction', tags=#{multiTool.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', toolIcon='add_to_photos', tags=#{merge.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', toolIcon='cut', tags=#{split.tags}, toolGroup='organize')}">
</div> </div>
<div <div id="groupOrganize" class="feature-group">
th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', toolIcon='rotate_right', tags=#{rotate.tags}, toolGroup='organize')}"> <div
</div> th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.organize})}">
<div </div>
th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', toolIcon='crop', tags=#{crop.tags}, toolGroup='organize')}"> <div class="feature-group-container">
</div> <div
<div th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', toolIcon='add_to_photos', tags=#{merge.tags}, toolGroup='organize')}">
th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', toolIcon='123', tags=#{add-page-numbers.tags}, toolGroup='other')}"> </div>
<div
th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', toolIcon='cut', tags=#{split.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', toolIcon='rotate_right', tags=#{rotate.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', toolIcon='crop', tags=#{crop.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', toolIcon='format_list_bulleted', tags=#{pdfOrganiser.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', toolIcon='delete', tags=#{removePages.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', toolIcon='dashboard', tags=#{pageLayout.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', toolIcon='fullscreen', tags=#{scalePages.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', toolIcon='upload', tags=#{extractPage.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', toolIcon='looks_one', tags=#{PdfToSinglePage.tags}, toolGroup='organize')}">
</div>
</div>
</div> </div>
<div <div id="groupConvertTo" class="feature-group">
th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', toolIcon='palette', tags=#{adjust-contrast.tags}, toolGroup='advance')}"> <div
</div> th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertTo})}">
<div </div>
th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf', toolIcon='image', tags=#{imageToPdf.tags}, toolGroup='image')}"> <div class="feature-group-container">
</div> <div
<div th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf', toolIcon='image', tags=#{imageToPdf.tags}, toolGroup='image')}">
th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', toolIcon='image', tags=#{pdfToImage.tags}, toolGroup='image')}"> </div>
<div
th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', toolIcon='draft', tags=#{fileToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', toolIcon='link', tags=#{URLToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', toolIcon='html', tags=#{HTMLToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', toolIcon='markdown', tags=#{MarkdownToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', toolIcon='book', tags=#{BookToPDF.tags}, toolGroup='convert')}">
</div>
</div>
</div> </div>
<div <div id="groupConvertFrom" class="feature-group">
th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', toolIcon='format_list_bulleted', tags=#{pdfOrganiser.tags}, toolGroup='organize')}"> <div
</div> th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertFrom})}">
<div </div>
th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', toolIcon='text_fields', tags=#{addImage.tags}, toolGroup='other')}"> <div class="feature-group-container">
</div> <div
<div th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', toolIcon='image', tags=#{pdfToImage.tags}, toolGroup='image')}">
th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', toolIcon='water_drop', tags=#{watermark.tags}, toolGroup='security')}"> </div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', toolIcon='picture_as_pdf', tags=#{pdfToPDFA.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', toolIcon='description', tags=#{PDFToWord.tags}, toolGroup='word')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', toolIcon='slideshow', tags=#{PDFToPresentation.tags}, toolGroup='ppt')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', toolIcon='text_fields', tags=#{PDFToText.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', toolIcon='html', tags=#{PDFToHTML.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', toolIcon='code', tags=#{PDFToXML.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', toolIcon='csv', tags=#{tableExtraxt.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', toolIcon='book', tags=#{PDFToBook.tags}, toolGroup='convert')}">
</div>
</div>
</div> </div>
<div <div id="groupSecurity" class="feature-group">
th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', toolIcon='draft', tags=#{fileToPDF.tags}, toolGroup='convert')}"> <div
</div> th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.security})}">
<div </div>
th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', toolIcon='delete', tags=#{removePages.tags}, toolGroup='organize')}"> <div class="feature-group-container">
</div> <div
<div th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', toolIcon='lock', tags=#{addPassword.tags}, toolGroup='security')}">
th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', toolIcon='lock', tags=#{addPassword.tags}, toolGroup='security')}"> </div>
</div> <div
<div th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', toolIcon='lock_open_right', tags=#{removePassword.tags}, toolGroup='security')}">
th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', toolIcon='lock_open_right', tags=#{removePassword.tags}, toolGroup='security')}"> </div>
</div> <div
<div th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', toolIcon='encrypted', tags=#{permissions.tags}, toolGroup='security')}">
th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}"> </div>
</div> <div
<div th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', toolIcon='signature', tags=#{sign.tags}, toolGroup='sign')}">
th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', toolIcon='assignment', tags=#{changeMetadata.tags}, toolGroup='other')}"> </div>
<div
th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', toolIcon='workspace_premium', tags=#{certSign.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-cert-sign', cardTitle=#{home.removeCertSign.title}, cardText=#{home.removeCertSign.desc}, cardLink='remove-cert-sign', toolIcon='remove_moderator', tags=#{removeCertSign.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', toolIcon='sanitizer', tags=#{sanitizePdf.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', toolIcon='ink_eraser', tags=#{autoRedact.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', toolIcon='approval', tags=#{AddStampRequest.tags}, toolGroup='security')}">
</div>
</div>
</div> </div>
<div <div id="groupView" class="feature-group">
th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', toolIcon='encrypted', tags=#{permissions.tags}, toolGroup='security')}"> <div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.edit})}">
</div> </div>
<div <div class="feature-group-container">
th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', toolIcon='quick_reference_all', tags=#{ocr.tags}, toolGroup='other')}"> <div
</div> th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', toolIcon='menu_book', tags=#{viewPdf.tags}, toolGroup='other')}">
<div </div>
th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', toolIcon='photo_library', tags=#{extractImages.tags}, toolGroup='other')}"> <div
th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', toolIcon='123', tags=#{add-page-numbers.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', toolIcon='text_fields', tags=#{addImage.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', toolIcon='water_drop', tags=#{watermark.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', toolIcon='assignment', tags=#{changeMetadata.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', toolIcon='quick_reference_all', tags=#{ocr.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', toolIcon='photo_library', tags=#{extractImages.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', toolIcon='scanner', tags=#{ScannerImageSplit.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', toolIcon='layers_clear', tags=#{flatten.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', toolIcon='scan_delete', tags=#{removeBlanks.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', toolIcon='thread_unread', tags=#{removeAnnotations.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', toolIcon='compare', tags=#{compare.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', toolIcon='info', tags=#{getPdfInfo.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-image-pdf', cardTitle=#{home.removeImagePdf.title}, cardText=#{home.removeImagePdf.desc}, cardLink='remove-image-pdf', toolIcon='remove_selection', tags=#{removeImagePdf.tags}, toolGroup='other')}">
</div>
</div>
</div> </div>
<div <div id="groupAdvanced" class="feature-group">
th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', toolIcon='picture_as_pdf', tags=#{pdfToPDFA.tags}, toolGroup='convert')}"> <div
</div> th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.advance})}">
<div </div>
th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', toolIcon='description', tags=#{PDFToWord.tags}, toolGroup='word')}"> <div class="feature-group-container">
</div> <div
<div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', toolIcon='family_history', tags=#{pipeline.tags}, toolGroup='advance')}">
th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', toolIcon='slideshow', tags=#{PDFToPresentation.tags}, toolGroup='ppt')}"> </div>
</div> <div
th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', toolIcon='construction', tags=#{multiTool.tags}, toolGroup='advance')}">
<div </div>
th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', toolIcon='text_fields', tags=#{PDFToText.tags}, toolGroup='convert')}"> <div
</div> th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', toolIcon='palette', tags=#{adjust-contrast.tags}, toolGroup='advance')}">
<div </div>
th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', toolIcon='html', tags=#{PDFToHTML.tags}, toolGroup='convert')}"> <div
</div> th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}">
<div </div>
th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', toolIcon='code', tags=#{PDFToXML.tags}, toolGroup='convert')}"> <div
</div> th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', toolIcon='build', tags=#{repair.tags}, toolGroup='advance')}">
<div </div>
th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', toolIcon='scanner', tags=#{ScannerImageSplit.tags}, toolGroup='advance')}"> <div
</div> th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', toolIcon='text_fields_alt', tags=#{auto-rename.tags}, toolGroup='advance')}">
<div </div>
th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', toolIcon='signature', tags=#{sign.tags}, toolGroup='sign')}"> <div
</div> th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', toolIcon='cut', tags=#{autoSplitPDF.tags}, toolGroup='advance')}">
<div </div>
th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', toolIcon='layers_clear', tags=#{flatten.tags}, toolGroup='other')}"> <div
</div> th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', toolIcon='javascript', tags=#{showJS.tags}, toolGroup='advance')}">
</div>
<div <div
th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', toolIcon='build', tags=#{repair.tags}, toolGroup='advance')}"> th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', toolIcon='vertical_split', tags=#{autoSizeSplitPDF.tags}, toolGroup='advance')}">
</div> </div>
<div <div
th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', toolIcon='scan_delete', tags=#{removeBlanks.tags}, toolGroup='other')}"> th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', toolIcon='layers', tags=#{overlay-pdfs.tags}, toolGroup='advance')}">
</div> </div>
<div <div
th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', toolIcon='thread_unread', tags=#{removeAnnotations.tags}, toolGroup='other')}"> th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', toolIcon='grid_on', tags=#{split-by-sections.tags}, toolGroup='advance')}">
</div> </div>
<div </div>
th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', toolIcon='compare', tags=#{compare.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', toolIcon='workspace_premium', tags=#{certSign.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-cert-sign', cardTitle=#{home.removeCertSign.title}, cardText=#{home.removeCertSign.desc}, cardLink='remove-cert-sign', toolIcon='remove_moderator', tags=#{removeCertSign.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', toolIcon='dashboard', tags=#{pageLayout.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', toolIcon='fullscreen', tags=#{scalePages.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', toolIcon='text_fields_alt', tags=#{auto-rename.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', toolIcon='cut', tags=#{autoSplitPDF.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', toolIcon='sanitizer', tags=#{sanitizePdf.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', toolIcon='link', tags=#{URLToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', toolIcon='html', tags=#{HTMLToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', toolIcon='markdown', tags=#{MarkdownToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', toolIcon='info', tags=#{getPdfInfo.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', toolIcon='upload', tags=#{extractPage.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', toolIcon='looks_one', tags=#{PdfToSinglePage.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', toolIcon='javascript', tags=#{showJS.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', toolIcon='ink_eraser', tags=#{autoRedact.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', toolIcon='csv', tags=#{tableExtraxt.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', toolIcon='vertical_split', tags=#{autoSizeSplitPDF.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', toolIcon='layers', tags=#{overlay-pdfs.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', toolIcon='grid_on', tags=#{split-by-sections.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', toolIcon='book', tags=#{BookToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', toolIcon='book', tags=#{PDFToBook.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', toolIcon='approval', tags=#{AddStampRequest.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-image-pdf', cardTitle=#{home.removeImagePdf.title}, cardText=#{home.removeImagePdf.desc}, cardLink='remove-image-pdf', toolIcon='remove_selection', tags=#{removeImagePdf.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='split-pdf-by-chapters', cardTitle=#{home.splitPdfByChapters.title}, cardText=#{home.splitPdfByChapters.desc}, cardLink='split-pdf-by-chapters', toolIcon='book', tags=#{splitPdfByChapters.tags}, toolGroup='organize')}">
</div> </div>
</div> </div>
</div> </div>
@ -245,7 +299,8 @@
<!-- Survey Modal --> <!-- Survey Modal -->
<div class="modal fade" id="surveyModal" tabindex="-1" role="dialog" aria-labelledby="surveyModalLabel" aria-hidden="true"> <div class="modal fade" id="surveyModal" tabindex="-1" role="dialog" aria-labelledby="surveyModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -253,12 +308,13 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p th:text="#{survey.changes}">Stirling-PDF has changed since the last survey! To find out more please check our blog post here:</h5> <p th:text="#{survey.description}">Stirling-PDF has no tracking so we want to hear from our users to improve
<a href="https://stirlingpdf.info/blog/stirling-pdf-survey-results" target="_blank" th:text="#{survey.changes2}">https://stirlingpdf.info/blog/stirling-pdf-survey-results</a> Stirling-PDF!</h5>
<p th:text="#{survey.changes2}">With these changes we are getting paid business support and funding</p>
<p th:text="#{survey.please}">Please consider taking our survey!</p> <p th:text="#{survey.please}">Please consider taking our survey!</p>
<p th:text="#{survey.disabled}">Survey popup will be disabled in following updates but available at foot of page)</p> <p th:text="#{survey.disabled}">Survey popup will be disabled in following updates but available at foot of
<a href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" target="_blank" class="btn btn-primary" id="takeSurvey"th:text="#{survey.button}" >Take Survey</a> page)</p>
<a href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" target="_blank" class="btn btn-primary"
id="takeSurvey" th:text="#{survey.button}">Take Survey</a>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div class="form-check mb-3"> <div class="form-check mb-3">
@ -274,35 +330,18 @@
</div> </div>
<script> <script>
/*
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
const surveyVersion = "2.0"; const surveyVersion = "1.1";
const modal = new bootstrap.Modal(document.getElementById('surveyModal')); const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
const dontShowAgain = document.getElementById('dontShowAgain'); const dontShowAgain = document.getElementById('dontShowAgain');
const takeSurveyButton = document.getElementById('takeSurvey'); const takeSurveyButton = document.getElementById('takeSurvey');
const viewThresholds = [5, 15, 30, 50, 75, 100, 150, 200]; if (localStorage.getItem('surveyVersion') !== surveyVersion || !localStorage.getItem('dontShowSurvey')) {
let pageViews = parseInt(localStorage.getItem('pageViews') || '0');
pageViews++;
localStorage.setItem('pageViews', pageViews.toString());
function shouldShowSurvey() {
if (localStorage.getItem('dontShowSurvey') === 'true' || localStorage.getItem('surveyTaken') === 'true') {
return false;
}
if (localStorage.getItem('surveyVersion') !== surveyVersion) {
return true;
}
return viewThresholds.includes(pageViews);
}
if (shouldShowSurvey()) {
modal.show(); modal.show();
} }
dontShowAgain.addEventListener('change', function() { dontShowAgain.addEventListener('change', function() {
if (this.checked) { if (this.checked) {
localStorage.setItem('dontShowSurvey', 'true'); localStorage.setItem('dontShowSurvey', 'true');
@ -314,11 +353,15 @@
}); });
takeSurveyButton.addEventListener('click', function() { takeSurveyButton.addEventListener('click', function() {
localStorage.setItem('surveyTaken', 'true'); localStorage.setItem('dontShowSurvey', 'true');
localStorage.setItem('surveyVersion', surveyVersion); localStorage.setItem('surveyVersion', surveyVersion);
modal.hide(); modal.hide();
}); });
});
if (localStorage.getItem('dontShowSurvey')) {
modal.hide();
}
});*/
</script> </script>

View File

@ -18,10 +18,10 @@
</div> </div>
<form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{'/api/v1/security/get-info-on-pdf'}"> <form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{'/api/v1/security/get-info-on-pdf'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, remoteCall='false', accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, remoteCall='false', accept='application/pdf')}"></div>
<br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{getPdfInfo.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{getPdfInfo.submit}"></button>
</form> </form>
<div class="container mt-5"> <div class="container mt-0">
<!-- Iterate over each main section in the JSON --> <!-- Iterate over each main section in the JSON -->
<div id="json-content"> <div id="json-content">
<!-- JavaScript will populate this section --> <!-- JavaScript will populate this section -->