Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56669f4247 | ||
|
|
22be1a1104 | ||
|
|
a80c585086 | ||
|
|
6d5dbd9729 | ||
|
|
0b4e3de455 | ||
|
|
8faef235a6 |
@@ -36,6 +36,7 @@ RUN apt-get update && \
|
|||||||
python3-pip \
|
python3-pip \
|
||||||
unoconv \
|
unoconv \
|
||||||
pngquant \
|
pngquant \
|
||||||
|
unpaper \
|
||||||
ocrmypdf && \
|
ocrmypdf && \
|
||||||
pip install --user --upgrade ocrmypdf
|
pip install --user --upgrade ocrmypdf
|
||||||
|
|
||||||
@@ -49,10 +50,12 @@ COPY build/libs/*.jar app.jar
|
|||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV LOG_LEVEL=INFO
|
ENV APP_HOME_NAME="Stirling PDF"
|
||||||
|
#ENV APP_HOME_DESCRIPTION="Personal PDF Website!"
|
||||||
|
#ENV APP_NAVBAR_NAME="Stirling PDF"
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
ENTRYPOINT ["java","-jar","/app.jar","-Dlogging.level=${LOG_LEVEL}"]
|
ENTRYPOINT java -jar /app.jar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
26
README.md
26
README.md
@@ -16,7 +16,6 @@ I will support and fix/add things to this if there is a demand [Discord](https:/
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Split PDFs into multiple files at specified page numbers or extract all pages as individual files.
|
- Split PDFs into multiple files at specified page numbers or extract all pages as individual files.
|
||||||
@@ -34,14 +33,14 @@ I will support and fix/add things to this if there is a demand [Discord](https:/
|
|||||||
- OCR on PDF (Using OCRMyPDF)
|
- OCR on PDF (Using OCRMyPDF)
|
||||||
- Edit metadata
|
- Edit metadata
|
||||||
- Dark mode support.
|
- Dark mode support.
|
||||||
- Custom download options
|
- Custom download options (see [here](https://github.com/Frooodle/Stirling-PDF/blob/main/images/settings.png) for example)
|
||||||
- Parallel file processing and downloads
|
- Parallel file processing and downloads
|
||||||
|
|
||||||
## Technologies used
|
## Technologies used
|
||||||
- Spring Boot + Thymeleaf
|
- Spring Boot + Thymeleaf
|
||||||
- PDFBox
|
- PDFBox
|
||||||
- LibreOffice for advanced conversions
|
- [LibreOffice](https://www.libreoffice.org/discover/libreoffice/) for advanced conversions
|
||||||
- OcrMyPdf https://github.com/ocrmypdf/OCRmyPDF
|
- [OcrMyPdf](https://github.com/ocrmypdf/OCRmyPDF)
|
||||||
- HTML, CSS, JavaScript
|
- HTML, CSS, JavaScript
|
||||||
- Docker
|
- Docker
|
||||||
|
|
||||||
@@ -75,9 +74,24 @@ services:
|
|||||||
image: frooodle/s-pdf
|
image: frooodle/s-pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Enable OCR/Compression feature
|
||||||
|
Please view https://github.com/Frooodle/Stirling-PDF/blob/main/HowToUseOCR.md
|
||||||
|
|
||||||
|
## Want to add your own language?
|
||||||
|
If you want to add your own language to Stirling-PDF please refer
|
||||||
|
https://github.com/Frooodle/Stirling-PDF/blob/main/HowToAddNewLanguage.md
|
||||||
|
|
||||||
|
And please create a PR to merge it back in so others can use it!
|
||||||
|
|
||||||
|
Also please note as i add new features i will google translate existing languages so that they dont lose support. This could mean that new features need grammer corrections as added.
|
||||||
|
|
||||||
## How to View
|
## How to View
|
||||||
1. Open a web browser and navigate to `http://localhost:8080/`
|
1. Open a web browser and navigate to `http://localhost:8080/`
|
||||||
2. Use the application by following the instructions on the website.
|
2. Use the application by following the instructions on the website.
|
||||||
|
|
||||||
## Note
|
|
||||||
The application is currently not thread-safe
|
## Customize App Name
|
||||||
|
Stirling PDF allows easy customization of the visible application name.
|
||||||
|
Simply use environment variables APP_HOME_NAME, APP_HOME_DESCRIPTION and APP_NAVBAR_NAME with Docker or Java.
|
||||||
|
If running Java directly, you can also pass these as properties using -D arguments.
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.0.4'
|
id 'org.springframework.boot' version '3.0.5'
|
||||||
id 'io.spring.dependency-management' version '1.1.0'
|
id 'io.spring.dependency-management' version '1.1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'stirling.software'
|
group = 'stirling.software'
|
||||||
version = '0.4.4'
|
version = '0.4.6'
|
||||||
sourceCompatibility = '17'
|
sourceCompatibility = '17'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@@ -19,6 +19,10 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
|
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio
|
||||||
|
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
|
||||||
|
|
||||||
|
|
||||||
//general PDF
|
//general PDF
|
||||||
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
|
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
|
||||||
|
|
||||||
|
|||||||
BIN
images/settings.png
Normal file
BIN
images/settings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 80 KiB |
@@ -5,9 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class SPdfApplication {
|
public class SPdfApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(SPdfApplication.class, args);
|
SpringApplication.run(SPdfApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,4 +11,33 @@ public class AppConfig {
|
|||||||
String version = getClass().getPackage().getImplementationVersion();
|
String version = getClass().getPackage().getImplementationVersion();
|
||||||
return (version != null) ? version : "0.3.3";
|
return (version != null) ? version : "0.3.3";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean(name = "appName")
|
||||||
|
public String appName() {
|
||||||
|
String appName = System.getProperty("APP_HOME_NAME");
|
||||||
|
if(appName == null)
|
||||||
|
appName = System.getenv("APP_HOME_NAME");
|
||||||
|
return (appName != null) ? appName : "Stirling PDF";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "navBarText")
|
||||||
|
public String navBarText() {
|
||||||
|
String navBarText = System.getProperty("APP_NAVBAR_NAME");
|
||||||
|
if(navBarText == null)
|
||||||
|
navBarText = System.getenv("APP_NAVBAR_NAME");
|
||||||
|
if(navBarText == null)
|
||||||
|
navBarText = System.getProperty("APP_HOME_NAME");
|
||||||
|
if(navBarText == null)
|
||||||
|
navBarText = System.getenv("APP_HOME_NAME");
|
||||||
|
|
||||||
|
return (navBarText != null) ? navBarText : "Stirling PDF";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "homeText")
|
||||||
|
public String homeText() {
|
||||||
|
String homeText = System.getProperty("APP_HOME_DESCRIPTION");
|
||||||
|
if(homeText == null)
|
||||||
|
homeText = System.getenv("APP_HOME_DESCRIPTION");
|
||||||
|
return (homeText != null) ? homeText : "null";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ public class Beans implements WebMvcConfigurer {
|
|||||||
@Bean
|
@Bean
|
||||||
public LocaleResolver localeResolver() {
|
public LocaleResolver localeResolver() {
|
||||||
SessionLocaleResolver slr = new SessionLocaleResolver();
|
SessionLocaleResolver slr = new SessionLocaleResolver();
|
||||||
slr.setDefaultLocale(Locale.US);
|
slr.setDefaultLocale(Locale.UK);
|
||||||
return slr;
|
return slr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ public class CompressController {
|
|||||||
command.add("--tesseract-timeout=0");
|
command.add("--tesseract-timeout=0");
|
||||||
command.add("--optimize");
|
command.add("--optimize");
|
||||||
command.add(String.valueOf(optimizeLevel));
|
command.add(String.valueOf(optimizeLevel));
|
||||||
|
command.add("--output-type");
|
||||||
|
command.add("pdf");
|
||||||
|
|
||||||
|
|
||||||
if (fastWebView != null && fastWebView) {
|
if (fastWebView != null && fastWebView) {
|
||||||
long fileSize = inputFile.getSize();
|
long fileSize = inputFile.getSize();
|
||||||
@@ -69,7 +72,7 @@ public class CompressController {
|
|||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
int returnCode = ProcessExecutor.runCommandWithOutputHandling(command);
|
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the optimized PDF file
|
// Read the optimized PDF file
|
||||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||||||
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
//import com.spire.pdf.*;
|
//import com.spire.pdf.*;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
@Controller
|
@Controller
|
||||||
public class OCRController {
|
public class OCRController {
|
||||||
|
|
||||||
@@ -41,10 +42,17 @@ public class OCRController {
|
|||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Semaphore semaphore = new Semaphore(2);
|
||||||
|
|
||||||
@PostMapping("/ocr-pdf")
|
@PostMapping("/ocr-pdf")
|
||||||
public ResponseEntity<byte[]> processPdfWithOCR(@RequestParam("fileInput") MultipartFile inputFile,
|
public ResponseEntity<byte[]> processPdfWithOCR(@RequestParam("fileInput") MultipartFile inputFile,
|
||||||
@RequestParam("languages") List<String> selectedLanguages,
|
@RequestParam("languages") List<String> selectedLanguages,
|
||||||
@RequestParam(name = "sidecar", required = false) Boolean sidecar) throws IOException, InterruptedException {
|
@RequestParam(name = "sidecar", required = false) Boolean sidecar,
|
||||||
|
@RequestParam(name = "deskew", required = false) Boolean deskew,
|
||||||
|
@RequestParam(name = "clean", required = false) Boolean clean,
|
||||||
|
@RequestParam(name = "clean-final", required = false) Boolean cleanFinal,
|
||||||
|
@RequestParam(name = "ocrType", required = false) String ocrType) throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
|
||||||
//--output-type pdfa
|
//--output-type pdfa
|
||||||
if (selectedLanguages == null || selectedLanguages.size() < 1) {
|
if (selectedLanguages == null || selectedLanguages.size() < 1) {
|
||||||
@@ -58,20 +66,50 @@ public class OCRController {
|
|||||||
// Prepare the output file path
|
// Prepare the output file path
|
||||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
|
|
||||||
|
// Prepare the output file path
|
||||||
|
Path sidecarTextPath = null;
|
||||||
|
|
||||||
// Run OCR Command
|
// Run OCR Command
|
||||||
String languageOption = String.join("+", selectedLanguages);
|
String languageOption = String.join("+", selectedLanguages);
|
||||||
List<String> command = new ArrayList<>(Arrays.asList("ocrmypdf","--verbose", "2", "--language", languageOption,
|
|
||||||
tempInputFile.toString(), tempOutputFile.toString()));
|
List<String> command = new ArrayList<>(Arrays.asList("ocrmypdf","--verbose", "2", "--output-type", "pdf"));
|
||||||
String sidecarFile = tempOutputFile.toString().replace(".pdf", ".txt");
|
|
||||||
|
|
||||||
if (sidecar != null && sidecar) {
|
if (sidecar != null && sidecar) {
|
||||||
|
sidecarTextPath = Files.createTempFile("sidecar", ".txt");
|
||||||
command.add("--sidecar");
|
command.add("--sidecar");
|
||||||
command.add(sidecarFile);
|
command.add(sidecarTextPath.toString());
|
||||||
}
|
}
|
||||||
int returnCode = ProcessExecutor.runCommandWithOutputHandling(command);
|
|
||||||
|
if (deskew != null && deskew) {
|
||||||
|
command.add("--deskew");
|
||||||
|
}
|
||||||
|
if (clean != null && clean) {
|
||||||
|
command.add("--clean");
|
||||||
|
}
|
||||||
|
if (cleanFinal != null && cleanFinal) {
|
||||||
|
command.add("--clean-final");
|
||||||
|
}
|
||||||
|
if (ocrType != null && !ocrType.equals("")) {
|
||||||
|
if("skip-text".equals(ocrType)) {
|
||||||
|
command.add("--skip-text");
|
||||||
|
} else if("force-ocr".equals(ocrType)) {
|
||||||
|
command.add("--force-ocr");
|
||||||
|
} else if("Normal".equals(ocrType)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command.addAll(Arrays.asList("--language", languageOption,
|
||||||
|
tempInputFile.toString(), tempOutputFile.toString()));
|
||||||
|
|
||||||
|
//Run CLI command
|
||||||
|
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the OCR processed PDF file
|
// Read the OCR processed PDF file
|
||||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
|
||||||
|
|
||||||
// Clean up the temporary files
|
// Clean up the temporary files
|
||||||
Files.delete(tempInputFile);
|
Files.delete(tempInputFile);
|
||||||
// Return the OCR processed PDF as a response
|
// Return the OCR processed PDF as a response
|
||||||
@@ -92,9 +130,9 @@ public class OCRController {
|
|||||||
zipOut.closeEntry();
|
zipOut.closeEntry();
|
||||||
|
|
||||||
// Add text file to the zip
|
// Add text file to the zip
|
||||||
ZipEntry txtEntry = new ZipEntry(sidecarFile);
|
ZipEntry txtEntry = new ZipEntry(outputFilename.replace(".pdf", ".txt"));
|
||||||
zipOut.putNextEntry(txtEntry);
|
zipOut.putNextEntry(txtEntry);
|
||||||
Files.copy(Paths.get(sidecarFile), zipOut);
|
Files.copy(sidecarTextPath, zipOut);
|
||||||
zipOut.closeEntry();
|
zipOut.closeEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +141,7 @@ public class OCRController {
|
|||||||
// Clean up the temporary zip file
|
// Clean up the temporary zip file
|
||||||
Files.delete(tempZipFile);
|
Files.delete(tempZipFile);
|
||||||
Files.delete(tempOutputFile);
|
Files.delete(tempOutputFile);
|
||||||
Files.delete(Paths.get(sidecarFile));
|
Files.delete(sidecarTextPath);
|
||||||
|
|
||||||
// Return the zip file containing both the PDF and the text file
|
// Return the zip file containing both the PDF and the text file
|
||||||
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ public class ConvertImgPDFController {
|
|||||||
if (singleImage) {
|
if (singleImage) {
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat)));
|
headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat)));
|
||||||
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
|
|
||||||
ResponseEntity<Resource> response = new ResponseEntity<>(new ByteArrayResource(result), headers, HttpStatus.OK);
|
ResponseEntity<Resource> response = new ResponseEntity<>(new ByteArrayResource(result), headers, HttpStatus.OK);
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public byte[] convertToPdf(MultipartFile inputFile) throws IOException, Interrup
|
|||||||
"-o",
|
"-o",
|
||||||
tempOutputFile.toString(),
|
tempOutputFile.toString(),
|
||||||
tempInputFile.toString()));
|
tempInputFile.toString()));
|
||||||
int returnCode = ProcessExecutor.runCommandWithOutputHandling(command);
|
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the converted PDF file
|
// Read the converted PDF file
|
||||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package stirling.software.SPDF.controller.converters;
|
||||||
|
|
||||||
|
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.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.itextpdf.xmp.XMPException;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
@Controller
|
||||||
|
public class ConvertPDFToPDFA {
|
||||||
|
|
||||||
|
@GetMapping("/pdf-to-pdfa")
|
||||||
|
public String pdfToPdfAForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "pdf-to-pdfa");
|
||||||
|
return "convert/pdf-to-pdfa";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/pdf-to-pdfa")
|
||||||
|
public ResponseEntity<byte[]> pdfToPdfA(
|
||||||
|
@RequestParam("fileInput") MultipartFile inputFile) throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
|
||||||
|
// Save the uploaded file to a temporary location
|
||||||
|
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
||||||
|
inputFile.transferTo(tempInputFile.toFile());
|
||||||
|
|
||||||
|
// Prepare the output file path
|
||||||
|
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
|
|
||||||
|
// Prepare the OCRmyPDF command
|
||||||
|
List<String> command = new ArrayList<>();
|
||||||
|
command.add("ocrmypdf");
|
||||||
|
command.add("--skip-text");
|
||||||
|
command.add("--tesseract-timeout=0");
|
||||||
|
command.add("--output-type");
|
||||||
|
command.add("pdfa");
|
||||||
|
command.add(tempInputFile.toString());
|
||||||
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
|
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
|
// Read the optimized PDF file
|
||||||
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
|
||||||
|
// Clean up the temporary files
|
||||||
|
Files.delete(tempInputFile);
|
||||||
|
Files.delete(tempOutputFile);
|
||||||
|
|
||||||
|
// Return the optimized PDF as a response
|
||||||
|
String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_PDFA.pdf";
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_PDF);
|
||||||
|
headers.setContentDispositionFormData("attachment", outputFilename);
|
||||||
|
return ResponseEntity.ok().headers(headers).body(pdfBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,13 +1,46 @@
|
|||||||
package stirling.software.SPDF.utils;
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
public class ProcessExecutor {
|
public class ProcessExecutor {
|
||||||
public static int runCommandWithOutputHandling(List<String> command) throws IOException, InterruptedException {
|
|
||||||
|
public enum Processes {
|
||||||
|
LIBRE_OFFICE,
|
||||||
|
OCR_MY_PDF
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map<Processes, ProcessExecutor> instances = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
private final Semaphore semaphore;
|
||||||
|
|
||||||
|
private ProcessExecutor(int semaphoreLimit) {
|
||||||
|
this.semaphore = new Semaphore(semaphoreLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProcessExecutor getInstance(Processes processType) {
|
||||||
|
return instances.computeIfAbsent(processType, key -> {
|
||||||
|
int semaphoreLimit = switch (key) {
|
||||||
|
case LIBRE_OFFICE -> 1;
|
||||||
|
case OCR_MY_PDF -> 2;
|
||||||
|
};
|
||||||
|
return new ProcessExecutor(semaphoreLimit);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public int runCommandWithOutputHandling(List<String> command) throws IOException, InterruptedException {
|
||||||
|
int exitCode = 1;
|
||||||
|
semaphore.acquire();
|
||||||
|
try {
|
||||||
|
|
||||||
|
System.out.print("Running command: " + String.join(" ", command));
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||||
Process process = processBuilder.start();
|
Process process = processBuilder.start();
|
||||||
|
|
||||||
@@ -41,7 +74,7 @@ public class ProcessExecutor {
|
|||||||
outputReaderThread.start();
|
outputReaderThread.start();
|
||||||
|
|
||||||
// Wait for the conversion process to complete
|
// Wait for the conversion process to complete
|
||||||
int exitCode = process.waitFor();
|
exitCode = process.waitFor();
|
||||||
|
|
||||||
// Wait for the reader threads to finish
|
// Wait for the reader threads to finish
|
||||||
errorReaderThread.join();
|
errorReaderThread.join();
|
||||||
@@ -59,7 +92,9 @@ public class ProcessExecutor {
|
|||||||
throw new IOException("Command process failed with exit code " + exitCode + ". Error message: " + errorMessage);
|
throw new IOException("Command process failed with exit code " + exitCode + ". Error message: " + errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
spring.http.multipart.max-file-size=1GB
|
spring.http.multipart.max-file-size=2GB
|
||||||
spring.http.multipart.max-request-size=1GB
|
spring.http.multipart.max-request-size=2GB
|
||||||
|
|
||||||
multipart.enabled=true
|
multipart.enabled=true
|
||||||
multipart.max-file-size=1000MB
|
multipart.max-file-size=2000MB
|
||||||
multipart.max-request-size=1000MB
|
multipart.max-request-size=2000MB
|
||||||
|
|
||||||
spring.servlet.multipart.max-file-size=1000MB
|
spring.servlet.multipart.max-file-size=2000MB
|
||||||
spring.servlet.multipart.max-request-size=1000MB
|
spring.servlet.multipart.max-request-size=2000MB
|
||||||
|
|
||||||
server.forward-headers-strategy=NATIVE
|
server.forward-headers-strategy=NATIVE
|
||||||
|
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ home.changeMetadata.desc = \u062A\u063A\u064A\u064A\u0631 / \u0625\u0632\u0627\u
|
|||||||
home.fileToPDF.title=\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
home.fileToPDF.title=\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
||||||
home.fileToPDF.desc=\u062A\u062D\u0648\u064A\u0644 \u0623\u064A \u0645\u0644\u0641 \u062A\u0642\u0631\u064A\u0628\u0627 \u0625\u0644\u0649 PDF (DOCX \u0648PNG \u0648XLS \u0648PPT \u0648TXT \u0648\u0627\u0644\u0645\u0632\u064A\u062F)
|
home.fileToPDF.desc=\u062A\u062D\u0648\u064A\u0644 \u0623\u064A \u0645\u0644\u0641 \u062A\u0642\u0631\u064A\u0628\u0627 \u0625\u0644\u0649 PDF (DOCX \u0648PNG \u0648XLS \u0648PPT \u0648TXT \u0648\u0627\u0644\u0645\u0632\u064A\u062F)
|
||||||
|
|
||||||
home.ocr.title=\u062A\u0634\u063A\u064A\u0644 OCR \u0639\u0644\u0649 PDF
|
home.ocr.title=\u062A\u0634\u063A\u064A\u0644 OCR \u0639\u0644\u0649 PDF \u0648 / \u0623\u0648 \u0645\u0633\u062D \u0636\u0648\u0626\u064A
|
||||||
home.ocr.desc=\u0645\u0633\u062D \u0648\u0627\u0643\u062A\u0634\u0627\u0641 \u0627\u0644\u0646\u0635 \u0645\u0646 \u0627\u0644\u0635\u0648\u0631 \u062F\u0627\u062E\u0644 PDF \u0648\u0625\u0639\u0627\u062F\u0629 \u0625\u0636\u0627\u0641\u062A\u0647 \u0643\u0646\u0635.
|
home.ocr.desc=\u064A\u0642\u0648\u0645 \u0628\u0631\u0646\u0627\u0645\u062C \u0627\u0644\u062A\u0646\u0638\u064A\u0641 \u0628\u0645\u0633\u062D \u0648\u0627\u0643\u062A\u0634\u0627\u0641 \u0627\u0644\u0646\u0635 \u0645\u0646 \u0627\u0644\u0635\u0648\u0631 \u062F\u0627\u062E\u0644 \u0645\u0644\u0641 PDF \u0648\u064A\u0639\u064A\u062F \u0625\u0636\u0627\u0641\u062A\u0647 \u0643\u0646\u0635
|
||||||
|
|
||||||
home.extractImages.title=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
home.extractImages.title=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
||||||
home.extractImages.desc=\u064A\u0633\u062A\u062E\u0631\u062C \u062C\u0645\u064A\u0639 \u0627\u0644\u0635\u0648\u0631 \u0645\u0646 \u0645\u0644\u0641 PDF \u0648\u064A\u062D\u0641\u0638\u0647\u0627 \u0641\u064A \u0627\u0644\u0631\u0645\u0632 \u0627\u0644\u0628\u0631\u064A\u062F\u064A
|
home.extractImages.desc=\u064A\u0633\u062A\u062E\u0631\u062C \u062C\u0645\u064A\u0639 \u0627\u0644\u0635\u0648\u0631 \u0645\u0646 \u0645\u0644\u0641 PDF \u0648\u064A\u062D\u0641\u0638\u0647\u0627 \u0641\u064A \u0627\u0644\u0631\u0645\u0632 \u0627\u0644\u0628\u0631\u064A\u062F\u064A
|
||||||
@@ -98,10 +98,18 @@ settings.downloadOption.3=\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u0645\u064
|
|||||||
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
|
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
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
OCR.title = OCR
|
ocr.title=\u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 / \u062A\u0646\u0638\u064A\u0641 \u0627\u0644\u0645\u0633\u062D \u0627\u0644\u0636\u0648\u0626\u064A
|
||||||
ocr.header=OCR (\u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u0623\u062D\u0631\u0641)
|
ocr.header=\u0645\u0633\u062D \u0627\u0644\u0645\u0633\u062D \u0627\u0644\u0636\u0648\u0626\u064A / \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 (\u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641)
|
||||||
ocr.selectText.1=\u062A\u062D\u062F\u064A\u062F \u0627\u0644\u0644\u063A\u0627\u062A \u0627\u0644\u062A\u064A \u0633\u064A\u062A\u0645 \u0627\u0643\u062A\u0634\u0627\u0641\u0647\u0627 \u062F\u0627\u062E\u0644 PDF (\u0627\u0644\u0644\u063A\u0627\u062A \u0627\u0644\u0645\u062F\u0631\u062C\u0629 \u0647\u064A \u062A\u0644\u0643 \u0627\u0644\u0645\u0643\u062A\u0634\u0641\u0629 \u062D\u0627\u0644\u064A\u0627):
|
ocr.selectText.1=\u062D\u062F\u062F \u0627\u0644\u0644\u063A\u0627\u062A \u0627\u0644\u062A\u064A \u0633\u064A\u062A\u0645 \u0627\u0643\u062A\u0634\u0627\u0641\u0647\u0627 \u062F\u0627\u062E\u0644 \u0645\u0644\u0641 PDF (\u0627\u0644\u0644\u063A\u0627\u062A \u0627\u0644\u0645\u062F\u0631\u062C\u0629 \u0647\u064A \u062A\u0644\u0643 \u0627\u0644\u062A\u064A \u062A\u0645 \u0627\u0643\u062A\u0634\u0627\u0641\u0647\u0627 \u062D\u0627\u0644\u064A\u064B\u0627):
|
||||||
ocr.selectText.2=\u0625\u0646\u062A\u0627\u062C \u0645\u0644\u0641 \u0646\u0635\u064A \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0646\u0635 OCR \u062C\u0646\u0628\u0627 \u0625\u0644\u0649 \u062C\u0646\u0628 \u0645\u0639 \u0645\u0644\u0641 PDF OCR'ed
|
ocr.selectText.2=\u0625\u0646\u062A\u0627\u062C \u0645\u0644\u0641 \u0646\u0635\u064A \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0646\u0635 OCR \u0628\u062C\u0627\u0646\u0628 \u0645\u0644\u0641 PDF \u0627\u0644\u0630\u064A \u062A\u0645 \u0625\u0639\u062F\u0627\u062F\u0647 \u0628\u0648\u0627\u0633\u0637\u0629 OCR
|
||||||
|
ocr.selectText.3=\u062A\u0645 \u0645\u0633\u062D \u0627\u0644\u0635\u0641\u062D\u0627\u062A \u0627\u0644\u0635\u062D\u064A\u062D\u0629 \u0636\u0648\u0626\u064A\u064B\u0627 \u0628\u0632\u0627\u0648\u064A\u0629 \u0645\u0646\u062D\u0631\u0641\u0629 \u0639\u0646 \u0637\u0631\u064A\u0642 \u062A\u062F\u0648\u064A\u0631\u0647\u0627 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u0641\u064A \u0645\u0643\u0627\u0646\u0647\u0627
|
||||||
|
ocr.selectText.4=\u0635\u0641\u062D\u0629 \u0646\u0638\u064A\u0641\u0629 \u0644\u0630\u0644\u0643 \u0645\u0646 \u063A\u064A\u0631 \u0627\u0644\u0645\u062D\u062A\u0645\u0644 \u0623\u0646 \u064A\u062C\u062F OCR \u0646\u0635\u064B\u0627 \u0641\u064A \u0636\u0648\u0636\u0627\u0621 \u0627\u0644\u062E\u0644\u0641\u064A\u0629. (\u0644\u0627 \u064A\u0648\u062C\u062F \u062A\u063A\u064A\u064A\u0631 \u0641\u064A \u0627\u0644\u0625\u062E\u0631\u0627\u062C)
|
||||||
|
ocr.selectText.5=\u0635\u0641\u062D\u0629 \u0646\u0638\u064A\u0641\u0629 \u060C \u0644\u0630\u0644\u0643 \u0645\u0646 \u063A\u064A\u0631 \u0627\u0644\u0645\u062D\u062A\u0645\u0644 \u0623\u0646 \u064A\u062C\u062F OCR \u0646\u0635\u064B\u0627 \u0641\u064A \u0636\u0648\u0636\u0627\u0621 \u0627\u0644\u062E\u0644\u0641\u064A\u0629 \u060C \u0648\u064A\u062D\u0627\u0641\u0638 \u0639\u0644\u0649 \u0627\u0644\u062A\u0646\u0638\u064A\u0641 \u0641\u064A \u0627\u0644\u0625\u062E\u0631\u0627\u062C.
|
||||||
|
ocr.selectText.6=\u064A\u062A\u062C\u0627\u0647\u0644 \u0627\u0644\u0635\u0641\u062D\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0646\u0635 \u062A\u0641\u0627\u0639\u0644\u064A \u060C \u0641\u0642\u0637 \u0635\u0641\u062D\u0627\u062A OCRs \u0627\u0644\u062A\u064A \u0647\u064A \u0635\u0648\u0631
|
||||||
|
ocr.selectText.7=\u0641\u0631\u0636 \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 \u060C \u0633\u064A\u0624\u062F\u064A \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 \u0639\u0644\u0649 \u0643\u0644 \u0635\u0641\u062D\u0629 \u0625\u0644\u0649 \u0625\u0632\u0627\u0644\u0629 \u062C\u0645\u064A\u0639 \u0639\u0646\u0627\u0635\u0631 \u0627\u0644\u0646\u0635 \u0627\u0644\u0623\u0635\u0644\u064A
|
||||||
|
ocr.selectText.8=\u0639\u0627\u062F\u064A (\u062E\u0637\u0623 \u0625\u0630\u0627 \u0643\u0627\u0646 PDF \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0646\u0635)
|
||||||
|
ocr.selectText.9=\u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0625\u0636\u0627\u0641\u064A\u0629
|
||||||
|
ocr.selectText.10=\u0648\u0636\u0639 \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641
|
||||||
ocr.help=\u064A\u0631\u062C\u0649 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0648\u062B\u0627\u0626\u0642 \u062D\u0648\u0644 \u0643\u064A\u0641\u064A\u0629 \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0647\u0630\u0627 \u0644\u0644\u063A\u0627\u062A \u0623\u062E\u0631\u0649 \u0648 / \u0623\u0648 \u0627\u0644\u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0644\u064A\u0633 \u0641\u064A \u0639\u0627\u0645\u0644 \u0627\u0644\u0625\u0631\u0633\u0627\u0621
|
ocr.help=\u064A\u0631\u062C\u0649 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0648\u062B\u0627\u0626\u0642 \u062D\u0648\u0644 \u0643\u064A\u0641\u064A\u0629 \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0647\u0630\u0627 \u0644\u0644\u063A\u0627\u062A \u0623\u062E\u0631\u0649 \u0648 / \u0623\u0648 \u0627\u0644\u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0644\u064A\u0633 \u0641\u064A \u0639\u0627\u0645\u0644 \u0627\u0644\u0625\u0631\u0633\u0627\u0621
|
||||||
ocr.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 OCRmyPDF \u0648 Tesseract \u0644 OCR.
|
ocr.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 OCRmyPDF \u0648 Tesseract \u0644 OCR.
|
||||||
ocr.submit=\u0645\u0639\u0627\u0644\u062C\u0629 PDF \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 OCR
|
ocr.submit=\u0645\u0639\u0627\u0644\u062C\u0629 PDF \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 OCR
|
||||||
@@ -287,3 +295,8 @@ xlsToPdf.title = \u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
|
|||||||
xlsToPdf.header=\u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
|
xlsToPdf.header=\u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
|
||||||
xlsToPdf.selectText.1=\u062D\u062F\u062F \u0648\u0631\u0642\u0629 \u0625\u0643\u0633\u0644 XLS \u0623\u0648 XLSX \u0644\u0644\u062A\u062D\u0648\u064A\u0644
|
xlsToPdf.selectText.1=\u062D\u062F\u062F \u0648\u0631\u0642\u0629 \u0625\u0643\u0633\u0644 XLS \u0623\u0648 XLSX \u0644\u0644\u062A\u062D\u0648\u064A\u0644
|
||||||
xlsToPdf.convert=\u062A\u062D\u0648\u064A\u0644
|
xlsToPdf.convert=\u062A\u062D\u0648\u064A\u0644
|
||||||
|
|
||||||
|
pdfToPDFA.title=PDF \u0625\u0644\u0649 PDF / A
|
||||||
|
pdfToPDFA.header=PDF \u0625\u0644\u0649 PDF / A
|
||||||
|
pdfToPDFA.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 OCRmyPDF \u0644\u062A\u062D\u0648\u064A\u0644 PDF / A.
|
||||||
|
pdfToPDFA.submit=\u062A\u062D\u0648\u064A\u0644
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ home.changeMetadata.desc=
|
|||||||
home.fileToPDF.title=Datei in PDF konvertieren
|
home.fileToPDF.title=Datei in PDF konvertieren
|
||||||
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
||||||
|
|
||||||
home.ocr.title=OCR auf PDF ausführen
|
home.ocr.title=Führe OCR auf PDF- und/oder Cleanup-Scans aus
|
||||||
home.ocr.desc=Scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu.
|
home.ocr.desc=Cleanup scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu.
|
||||||
|
|
||||||
home.extractImages.title=Bilder extrahieren
|
home.extractImages.title=Bilder extrahieren
|
||||||
home.extractImages.desc=Extrahiert alle Bilder aus einer PDF-Datei und speichert sie als Zip-Datei
|
home.extractImages.desc=Extrahiert alle Bilder aus einer PDF-Datei und speichert sie als Zip-Datei
|
||||||
@@ -93,10 +93,18 @@ settings.downloadOption.3=Datei herunterladen
|
|||||||
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR
|
ocr.title=OCR / Scan-Bereinigung
|
||||||
ocr.header=OCR (Optische Zeichenerkennung)
|
ocr.header=Scans bereinigen / OCR (Optical Character Recognition)
|
||||||
ocr.selectText.1=Wählen Sie die Sprachen aus, die in der PDF-Datei erkannt werden sollen (die aufgelisteten sind die aktuell erkannten):
|
ocr.selectText.1=Sprachen auswählen, die im PDF erkannt werden sollen (die aufgelisteten sind die aktuell erkannten):
|
||||||
ocr.selectText.2=Textdatei mit OCR-Text neben der OCR-PDF-Datei erstellen
|
ocr.selectText.2=Textdatei erzeugen, die OCR-Text neben dem OCR-bearbeiteten PDF enthält
|
||||||
|
ocr.selectText.3=Korrekte Seiten wurden in einem schiefen Winkel gescannt, indem sie wieder an ihren Platz gedreht wurden
|
||||||
|
ocr.selectText.4=Seite säubern, daher ist es weniger wahrscheinlich, dass OCR Text im Hintergrundrauschen findet. (Keine Ausgangsänderung)
|
||||||
|
ocr.selectText.5=Seite säubern, sodass es weniger wahrscheinlich ist, dass OCR Text im Hintergrundrauschen findet, Bereinigung der Ausgabe wird beibehalten.
|
||||||
|
ocr.selectText.6=Ignoriert Seiten mit interaktivem Text, nur OCR-Seiten, die Bilder sind
|
||||||
|
ocr.selectText.7=OCR erzwingen, OCR wird jede Seite entfernen und alle ursprünglichen Textelemente entfernen
|
||||||
|
ocr.selectText.8=Normal (Fehler, wenn PDF Text enthält)
|
||||||
|
ocr.selectText.9=Zusätzliche Einstellungen
|
||||||
|
ocr.selectText.10=OCR-Modus
|
||||||
ocr.help=Bitte lesen Sie diese Dokumentation, um zu erfahren, wie Sie dies für andere Sprachen verwenden und/oder nicht in Docker verwenden können
|
ocr.help=Bitte lesen Sie diese Dokumentation, um zu erfahren, wie Sie dies für andere Sprachen verwenden und/oder nicht in Docker verwenden können
|
||||||
ocr.credit=Dieser Dienst verwendet OCRmyPDF und Tesseract für OCR.
|
ocr.credit=Dieser Dienst verwendet OCRmyPDF und Tesseract für OCR.
|
||||||
ocr.submit=PDF mit OCR verarbeiten
|
ocr.submit=PDF mit OCR verarbeiten
|
||||||
@@ -289,7 +297,10 @@ xlsToPdf.selectText.1=XLS- oder XLSX-Excel-Tabelle zum Konvertieren ausw
|
|||||||
xlsToPdf.convert=konvertieren
|
xlsToPdf.convert=konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
pdfToPDFA.title=PDF zu PDF/A
|
||||||
|
pdfToPDFA.header=PDF zu PDF/A
|
||||||
|
pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung
|
||||||
|
pdfToPDFA.submit=Konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -76,12 +76,15 @@ home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
|||||||
home.fileToPDF.title=Convert file to PDF
|
home.fileToPDF.title=Convert file to PDF
|
||||||
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
||||||
|
|
||||||
home.ocr.title=Run OCR on PDF
|
home.ocr.title=Run OCR on PDF and/or Cleanup scans
|
||||||
home.ocr.desc=Scans and detects text from images within a PDF and re-adds it as text.
|
home.ocr.desc=Cleanup scans and detects text from images within a PDF and re-adds it as text.
|
||||||
|
|
||||||
home.extractImages.title=Extract Images
|
home.extractImages.title=Extract Images
|
||||||
home.extractImages.desc=Extracts all images from a PDF and saves them to zip
|
home.extractImages.desc=Extracts all images from a PDF and saves them to zip
|
||||||
|
|
||||||
|
home.pdfToPDFA.title=Convert PDF to PDF/A
|
||||||
|
home.pdfToPDFA.desc=Convert PDF to PDF/A for long-term storage
|
||||||
|
|
||||||
|
|
||||||
navbar.settings=Settings
|
navbar.settings=Settings
|
||||||
settings.title=Settings
|
settings.title=Settings
|
||||||
@@ -93,15 +96,28 @@ settings.downloadOption.2=Open in new window
|
|||||||
settings.downloadOption.3=Download file
|
settings.downloadOption.3=Download file
|
||||||
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR
|
ocr.title=OCR / Scan Cleanup
|
||||||
ocr.header=OCR (Optical Character Recognition)
|
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.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.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 interacive 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.help=Please read this documentation on how to use this for other languages and/or use not in docker
|
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.credit=This service uses OCRmyPDF and Tesseract for OCR.
|
||||||
ocr.submit=Process PDF with OCR
|
ocr.submit=Process PDF with OCR
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extractImages.title=Extract Images
|
extractImages.title=Extract Images
|
||||||
extractImages.header=Extract Images
|
extractImages.header=Extract Images
|
||||||
extractImages.selectText=Select image format to convert extracted images to
|
extractImages.selectText=Select image format to convert extracted images to
|
||||||
@@ -286,6 +302,10 @@ xlsToPdf.convert=convert
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,298 +0,0 @@
|
|||||||
###########
|
|
||||||
# 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=Page Order (Enter a comma-separated list of page numbers) :
|
|
||||||
goToPage=Go
|
|
||||||
true=True
|
|
||||||
false=False
|
|
||||||
unknown=Unknown
|
|
||||||
save=Save
|
|
||||||
close=Close
|
|
||||||
|
|
||||||
#############
|
|
||||||
# HOME-PAGE #
|
|
||||||
#############
|
|
||||||
home.desc=Your locally hosted one-stop-shop for all your PDF needs.
|
|
||||||
|
|
||||||
navbar.convert=Convert
|
|
||||||
navbar.security=Security
|
|
||||||
navbar.other=Other
|
|
||||||
navbar.darkmode=Dark Mode
|
|
||||||
|
|
||||||
home.merge.title=Merge PDFs
|
|
||||||
home.merge.desc=Easily merge multiple PDFs into one.
|
|
||||||
|
|
||||||
home.split.title=Split PDFs
|
|
||||||
home.split.desc=Split PDFs into multiple documents
|
|
||||||
|
|
||||||
home.rotate.title=Rotate PDFs
|
|
||||||
home.rotate.desc=Easily rotate your PDFs.
|
|
||||||
|
|
||||||
home.imageToPdf.title=Image to PDF
|
|
||||||
home.imageToPdf.desc=Convert a images (PNG, JPEG, GIF) to PDF.
|
|
||||||
|
|
||||||
home.pdfToImage.title=PDF to Image
|
|
||||||
home.pdfToImage.desc=Convert a PDF to a image. (PNG, JPEG, GIF)
|
|
||||||
|
|
||||||
home.pdfOrganiser.title=PDF Organizer
|
|
||||||
home.pdfOrganiser.desc=Remove/Rearrange pages in any order
|
|
||||||
|
|
||||||
home.addImage.title=Add image onto PDF
|
|
||||||
home.addImage.desc=Adds a image onto a set location on the PDF (Work in progress)
|
|
||||||
|
|
||||||
home.watermark.title=Add Watermark
|
|
||||||
home.watermark.desc=Add a custom watermark to your PDF document.
|
|
||||||
|
|
||||||
home.remove-watermark.title=Remove Watermark
|
|
||||||
home.remove-watermark.desc=Remove watermarks from your PDF document.
|
|
||||||
|
|
||||||
home.permissions.title=Change Permissions
|
|
||||||
home.permissions.desc=Change the permissions of your PDF document
|
|
||||||
|
|
||||||
home.removePages.title=Remove Pages
|
|
||||||
home.removePages.desc=Delete unwanted pages from your PDF document.
|
|
||||||
|
|
||||||
home.addPassword.title=Add Password
|
|
||||||
home.addPassword.desc=Encrypt your PDF document with a password.
|
|
||||||
|
|
||||||
home.removePassword.title=Remove Password
|
|
||||||
home.removePassword.desc=Remove password protection from your PDF document.
|
|
||||||
|
|
||||||
home.compressPdfs.title=Compress PDFs
|
|
||||||
home.compressPdfs.desc=Compress PDFs to reduce their file size.
|
|
||||||
|
|
||||||
home.changeMetadata.title=Change Metadata
|
|
||||||
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
|
||||||
|
|
||||||
home.fileToPDF.title=Convert file to PDF
|
|
||||||
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
|
||||||
|
|
||||||
home.ocr.title=Run OCR on PDF
|
|
||||||
home.ocr.desc=Scans and detects text from images within a PDF and re-adds it as text.
|
|
||||||
|
|
||||||
home.extractImages.title=Extract Images
|
|
||||||
home.extractImages.desc=Extracts all images from a PDF and saves them to zip
|
|
||||||
|
|
||||||
|
|
||||||
navbar.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
|
|
||||||
|
|
||||||
#OCR
|
|
||||||
ocr.title=OCR
|
|
||||||
ocr.header=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.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.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
|
|
||||||
|
|
||||||
|
|
||||||
#Add image
|
|
||||||
addImage.title=Add Image
|
|
||||||
addImage.header=Add image to PDF (Work in progress)
|
|
||||||
addImage.submit=Add image
|
|
||||||
|
|
||||||
#compress
|
|
||||||
compress.title=Compress
|
|
||||||
compress.header=Compress PDF
|
|
||||||
compress.credit=This service uses OCRmyPDF for PDF Compress/Optimisation.
|
|
||||||
compress.selectText.1=Optimization level:
|
|
||||||
compress.selectText.2=0 (No optimization)
|
|
||||||
compress.selectText.3=1 (Default, lossless optimization)
|
|
||||||
compress.selectText.4=2 (Lossy optimization)
|
|
||||||
compress.selectText.5=3 (Lossy optimization, more aggressive)
|
|
||||||
compress.selectText.6=Enable fast web view (linearize PDF)
|
|
||||||
compress.selectText.7=Enable lossy JBIG2 encoding
|
|
||||||
compress.submit=Compress
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
|
||||||
merge.title=Merge
|
|
||||||
merge.header=Merge multiple PDFs (2+)
|
|
||||||
merge.submit=Merge
|
|
||||||
|
|
||||||
#pdfOrganiser
|
|
||||||
pdfOrganiser.title=Page Organizer
|
|
||||||
pdfOrganiser.header=PDF Page Organizer
|
|
||||||
pdfOrganiser.submit=Rearrange Pages
|
|
||||||
|
|
||||||
|
|
||||||
#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=Color type
|
|
||||||
pdfToImage.color=Color
|
|
||||||
pdfToImage.grey=Grayscale
|
|
||||||
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=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
|
|
||||||
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.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.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
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -81,8 +81,8 @@ home.changeMetadata.desc=Modifier/Supprimer/Ajouter des m
|
|||||||
home.fileToPDF.title=Convertir un fichier en PDF
|
home.fileToPDF.title=Convertir un fichier en PDF
|
||||||
home.fileToPDF.desc=Convertissez presque n\u2019importe quel fichier en PDF (DOCX, PNG, XLS, PPT, TXT et plus)
|
home.fileToPDF.desc=Convertissez presque n\u2019importe quel fichier en PDF (DOCX, PNG, XLS, PPT, TXT et plus)
|
||||||
|
|
||||||
home.ocr.title=Exécuter OCR sur PDF
|
home.ocr.title=Exécuter l'OCR sur les scans PDF et/ou de nettoyage
|
||||||
home.ocr.desc=Analyse et détecte le texte des images d\u2019un fichier PDF et le rajoute en tant que texte.
|
home.ocr.desc=Le nettoyage analyse et détecte le texte des images dans un PDF et le rajoute en tant que texte.
|
||||||
|
|
||||||
home.extractImages.title=Extraire les images
|
home.extractImages.title=Extraire les images
|
||||||
home.extractImages.desc=Extrait toutes les images d\u2019un PDF et les enregistre au format zip
|
home.extractImages.desc=Extrait toutes les images d\u2019un PDF et les enregistre au format zip
|
||||||
@@ -100,10 +100,18 @@ settings.zipThreshold=Zip les fichiers lorsque le nombre de fichiers t
|
|||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR
|
ocr.title=OCR / Nettoyage de numérisation
|
||||||
ocr.header=OCR (reconnaissance optique de caractères)
|
ocr.header=Nettoyage des scans / OCR (reconnaissance optique des caractères)
|
||||||
ocr.selectText.1=Sélectionnez les langues à détecter dans le fichier PDF (celles répertoriées sont celles actuellement détectées) :
|
ocr.selectText.1=Sélectionnez les langues à détecter dans le PDF (celles répertoriées sont celles actuellement détectées) :
|
||||||
ocr.selectText.2=Produire un fichier texte contenant du texte OCR à côté du PDF OCR
|
ocr.selectText.2=Produire un fichier texte contenant du texte OCR avec le PDF OCR
|
||||||
|
ocr.selectText.3=Les pages correctes ont été numérisées à un angle oblique en les remettant en place
|
||||||
|
ocr.selectText.4=Nettoyer la page pour qu'il soit moins probable que l'OCR trouve du texte dans le bruit de fond. (Pas de changement de sortie)
|
||||||
|
ocr.selectText.5=Nettoyer la page afin qu'il soit moins probable que l'OCR trouve du texte dans le bruit de fond, maintient le nettoyage dans la sortie.
|
||||||
|
ocr.selectText.6=Ignore les pages contenant du texte interactif, seulement les pages OCR qui sont des images
|
||||||
|
ocr.selectText.7=Forcer l'OCR, OCR chaque page supprimera tous les éléments de texte d'origine
|
||||||
|
ocr.selectText.8=Normal (Erreur si le PDF contient du texte)
|
||||||
|
ocr.selectText.9=Paramètres supplémentaires
|
||||||
|
ocr.selectText.10=Mode ROC
|
||||||
ocr.help=Veuillez lire cette documentation pour savoir comment l\u2019utiliser pour d\u2019autres langues et/ou une utilisation non dans docker
|
ocr.help=Veuillez lire cette documentation pour savoir comment l\u2019utiliser pour d\u2019autres langues et/ou une utilisation non dans docker
|
||||||
ocr.credit=Ce service utilise OCRmyPDF et Tesseract pour l\u2019OCR.
|
ocr.credit=Ce service utilise OCRmyPDF et Tesseract pour l\u2019OCR.
|
||||||
ocr.submit=Traiter PDF avec OCR
|
ocr.submit=Traiter PDF avec OCR
|
||||||
@@ -292,3 +300,7 @@ xlsToPdf.header=Excel en PDF
|
|||||||
xlsToPdf.selectText.1=Sélectionnez une feuille Excel XLS ou XLSX à convertir
|
xlsToPdf.selectText.1=Sélectionnez une feuille Excel XLS ou XLSX à convertir
|
||||||
xlsToPdf.convert=convertir
|
xlsToPdf.convert=convertir
|
||||||
|
|
||||||
|
pdfToPDFA.title=PDF vers PDF/A
|
||||||
|
pdfToPDFA.header=PDF vers PDF/A
|
||||||
|
pdfToPDFA.credit=Ce service utilise OCRmyPDF pour la conversion PDF/A
|
||||||
|
pdfToPDFA.submit=Convertir
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="y">Y</label> <input type="number" class="form-control" id="y" name="y" step="0.01" required>
|
<label for="y">Y</label> <input type="number" class="form-control" id="y" name="y" step="0.01" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{addImage.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{addImage.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<input type="checkbox" name="jbig2Lossy" id="jbig2Lossy">
|
<input type="checkbox" name="jbig2Lossy" id="jbig2Lossy">
|
||||||
<label for="jbig2Lossy" th:text="#{compress.selectText.7}"></label>
|
<label for="jbig2Lossy" th:text="#{compress.selectText.7}"></label>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{compress.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{compress.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<p class="mt-3" th:text="#{compress.credit}"></p>
|
<p class="mt-3" th:text="#{compress.credit}"></p>
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<form method="post" enctype="multipart/form-data" th:action="@{file-to-pdf}">
|
<form method="post" enctype="multipart/form-data" th:action="@{file-to-pdf}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
<p class="mt-3" th:text="#{fileToPDF.credit}"></p>
|
<p class="mt-3" th:text="#{fileToPDF.credit}"></p>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br> <br>
|
<br> <br>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
|
||||||
<script>
|
<script>
|
||||||
$('#fileInput-input').on('change', function() {
|
$('#fileInput-input').on('change', function() {
|
||||||
var files = document.getElementById("fileInput-input").files;
|
var files = document.getElementById("fileInput-input").files;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<label for="dpi">DPI:</label>
|
<label for="dpi">DPI:</label>
|
||||||
<input type="number" name="dpi" class="form-control" id="dpi" min="1" max="100" step="1" value="30" required>
|
<input type="number" name="dpi" class="form-control" id="dpi" min="1" max="100" step="1" value="30" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
31
src/main/resources/templates/convert/pdf-to-pdfa.html
Normal file
31
src/main/resources/templates/convert/pdf-to-pdfa.html
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
|
<th:block th:insert="~{fragments/common :: head(title=#{pdfToPDFA.title})}"></th:block>
|
||||||
|
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="content-wrap">
|
||||||
|
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
|
||||||
|
<br> <br>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 th:text="#{pdfToPDFA.header}"></h2>
|
||||||
|
<p>Currently doesn't work for multiple inputs at once</p>
|
||||||
|
<form method="post" enctype="multipart/form-data" th:action="@{pdf-to-pdfa}">
|
||||||
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
|
<br>
|
||||||
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToPDFA.submit}"></button>
|
||||||
|
</form>
|
||||||
|
<p class="mt-3" th:text="#{pdfToPDFA.credit}"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<option value="gif">GIF</option>
|
<option value="gif">GIF</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{extractImages.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{extractImages.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<!-- Metadata -->
|
<!-- Metadata -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
<title th:text="'S-PDF ' + ${title}"></title>
|
<title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title>
|
||||||
<link rel="shortcut icon" href="favicon.svg">
|
<link rel="shortcut icon" href="favicon.svg">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
@@ -84,6 +84,10 @@ function toggleDarkMode() {
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
$('form').submit(function(event) {
|
$('form').submit(function(event) {
|
||||||
|
var processing = "Processing..."
|
||||||
|
var submitButtonText = $('#submitBtn').text()
|
||||||
|
|
||||||
|
$('#submitBtn').text('Processing...');
|
||||||
console.log("start download code")
|
console.log("start download code")
|
||||||
var files = $('#fileInput-input')[0].files;
|
var files = $('#fileInput-input')[0].files;
|
||||||
var url = this.action;
|
var url = this.action;
|
||||||
@@ -188,25 +192,30 @@ function toggleDarkMode() {
|
|||||||
// Create an error message to display to the user
|
// Create an error message to display to the user
|
||||||
const message = `${errorMessage}\n\n${stackTrace}`;
|
const message = `${errorMessage}\n\n${stackTrace}`;
|
||||||
|
|
||||||
|
$('#submitBtn').text(submitButtonText);
|
||||||
|
|
||||||
// Display the error message to the user
|
// Display the error message to the user
|
||||||
alert(message);
|
alert(message);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
$('#submitBtn').text(submitButtonText);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function submitMultiPdfForm(event, url) {
|
async function submitMultiPdfForm(event, url) {
|
||||||
// Get the selected PDF files
|
// Get the selected PDF files
|
||||||
var files = $('#fileInput-input')[0].files;
|
let files = $('#fileInput-input')[0].files;
|
||||||
|
|
||||||
// Get the existing form data
|
// Get the existing form data
|
||||||
var formData = new FormData($('form')[0]);
|
let formData = new FormData($('form')[0]);
|
||||||
formData.delete('fileInput');
|
formData.delete('fileInput');
|
||||||
|
|
||||||
// Show the progress bar
|
// Show the progress bar
|
||||||
$('#progressBarContainer').show();
|
$('#progressBarContainer').show();
|
||||||
|
|
||||||
// Initialize the progress bar
|
// Initialize the progress bar
|
||||||
var progressBar = $('#progressBar');
|
let progressBar = $('#progressBar');
|
||||||
progressBar.css('width', '0%');
|
progressBar.css('width', '0%');
|
||||||
progressBar.attr('aria-valuenow', 0);
|
progressBar.attr('aria-valuenow', 0);
|
||||||
progressBar.attr('aria-valuemax', files.length);
|
progressBar.attr('aria-valuemax', files.length);
|
||||||
@@ -221,39 +230,51 @@ function toggleDarkMode() {
|
|||||||
jszip = new JSZip();
|
jszip = new JSZip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Submit each PDF file in parallel
|
// Submit each PDF file in parallel
|
||||||
var promises = [];
|
let promises = [];
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
var promise = new Promise(function(resolve, reject) {
|
let promise = new Promise(async function(resolve, reject) {
|
||||||
var fileFormData = new FormData();
|
let fileFormData = new FormData();
|
||||||
fileFormData.append('fileInput', files[i]);
|
fileFormData.append('fileInput', files[i]);
|
||||||
for (var pair of formData.entries()) {
|
for (let pair of formData.entries()) {
|
||||||
fileFormData.append(pair[0], pair[1]);
|
fileFormData.append(pair[0], pair[1]);
|
||||||
}
|
}
|
||||||
console.log(fileFormData);
|
console.log(fileFormData);
|
||||||
|
|
||||||
fetch(url, {
|
try {
|
||||||
|
let response = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: fileFormData
|
body: fileFormData
|
||||||
}).then(function(response) {
|
});
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
throw new Error('Received null response for file ' + i);
|
throw new Error('Received null response for file ' + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Error submitting request for file ${i}: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let contentDisposition = response.headers.get('content-disposition');
|
||||||
|
let fileName = "file.pdf"
|
||||||
|
if (!contentDisposition) {
|
||||||
|
//throw new Error('Content-Disposition header not found for file ' + i);
|
||||||
|
} else {
|
||||||
|
fileName = contentDisposition.split('filename=')[1].replace(/"/g, '');
|
||||||
|
}
|
||||||
console.log('Received response for file ' + i + ': ' + response);
|
console.log('Received response for file ' + i + ': ' + response);
|
||||||
|
|
||||||
var contentDisposition = response.headers.get('content-disposition');
|
|
||||||
var fileName = contentDisposition.split('filename=')[1].replace(/"/g, '');
|
|
||||||
|
|
||||||
response.blob().then(function (blob) {
|
|
||||||
|
let blob = await response.blob();
|
||||||
if (zipFiles) {
|
if (zipFiles) {
|
||||||
// Add the file to the ZIP archive
|
// Add the file to the ZIP archive
|
||||||
jszip.file(fileName, blob);
|
jszip.file(fileName, blob);
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
// Download the file directly
|
// Download the file directly
|
||||||
var url = window.URL.createObjectURL(blob);
|
let url = window.URL.createObjectURL(blob);
|
||||||
var a = document.createElement('a');
|
let a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = fileName;
|
a.download = fileName;
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
@@ -261,29 +282,25 @@ function toggleDarkMode() {
|
|||||||
a.remove();
|
a.remove();
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
});
|
} catch (error) {
|
||||||
|
|
||||||
}).catch(function(error) {
|
|
||||||
console.error('Error submitting request for file ' + i + ': ' + error);
|
console.error('Error submitting request for file ' + i + ': ' + error);
|
||||||
|
|
||||||
// Set default values or fallbacks for error properties
|
// Set default values or fallbacks for error properties
|
||||||
var status = error && error.status || 500;
|
let status = error && error.status || 500;
|
||||||
var statusText = error && error.statusText || 'Internal Server Error';
|
let statusText = error && error.statusText || 'Internal Server Error';
|
||||||
var message = error && error.message || 'An error occurred while processing your request.';
|
let message = error && error.message || 'An error occurred while processing your request.';
|
||||||
|
|
||||||
// Reject the Promise to signal that the request has failed
|
// Reject the Promise to signal that the request has failed
|
||||||
reject();
|
reject();
|
||||||
// Redirect to error page with Spring Boot error parameters
|
// Redirect to error page with Spring Boot error parameters
|
||||||
var url = '/error?status=' + status + '&error=' + encodeURIComponent(statusText) + '&message=' + encodeURIComponent(message);
|
let url = '/error?status=' + status + '&error=' + encodeURIComponent(statusText) + '&message=' + encodeURIComponent(message);
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update the progress bar as each request finishes
|
// Update the progress bar as each request finishes
|
||||||
promise.then(function() {
|
promise.then(function() {
|
||||||
var progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length);
|
updateProgressBar(progressBar, files);
|
||||||
progressBar.css('width', progress + '%');
|
|
||||||
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
promises.push(promise);
|
promises.push(promise);
|
||||||
@@ -302,17 +319,26 @@ function toggleDarkMode() {
|
|||||||
|
|
||||||
// After all requests are finished, download the ZIP file if needed
|
// After all requests are finished, download the ZIP file if needed
|
||||||
if (zipFiles) {
|
if (zipFiles) {
|
||||||
jszip.generateAsync({ type: "blob" }).then(function (content) {
|
try {
|
||||||
var url = window.URL.createObjectURL(content);
|
let content = await jszip.generateAsync({ type: "blob" });
|
||||||
var a = document.createElement('a');
|
let url = window.URL.createObjectURL(content);
|
||||||
|
let a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = "files.zip";
|
a.download = "files.zip";
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
a.remove();
|
a.remove();
|
||||||
});
|
} catch (error) {
|
||||||
|
console.error('Error generating ZIP file: ' + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function updateProgressBar(progressBar, files) {
|
||||||
|
let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length);
|
||||||
|
progressBar.css('width', progress + '%');
|
||||||
|
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,6 @@
|
|||||||
<a href="https://github.com/Frooodle/Stirling-PDF" target="_blank" class="mx-1"><img src="images/github.svg"></img></a>
|
<a href="https://github.com/Frooodle/Stirling-PDF" target="_blank" class="mx-1"><img src="images/github.svg"></img></a>
|
||||||
<a href="https://hub.docker.com/r/frooodle/s-pdf" target="_blank" class="mx-1"><img src="images/docker.svg"></img></a>
|
<a href="https://hub.docker.com/r/frooodle/s-pdf" target="_blank" class="mx-1"><img src="images/docker.svg"></img></a>
|
||||||
<a href="https://discord.gg/Cn8pWhQRxZ" target="_blank" class="mx-1"><img src="images/discord.svg"></img></a>
|
<a href="https://discord.gg/Cn8pWhQRxZ" target="_blank" class="mx-1"><img src="images/discord.svg"></img></a>
|
||||||
|
<div th:if="${@appName} != 'Stirling PDF'" class="mt-2" style="color: grey;">Powered by Stirling PDF</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@@ -109,7 +109,7 @@ function compareVersions(version1, version2) {
|
|||||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
<div class="container ">
|
<div class="container ">
|
||||||
|
|
||||||
<a class="navbar-brand" href="#" th:href="@{/}">Stirling PDF</a>
|
<a class="navbar-brand" href="#" th:href="@{/}" th:text="${@navBarText}"></a>
|
||||||
|
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
@@ -127,12 +127,13 @@ function compareVersions(version1, version2) {
|
|||||||
|
|
||||||
<li class="nav-item"><a class="nav-link" href="#" th:href="@{rotate-pdf}" th:classappend="${currentPage}=='rotate-pdf' ? 'active' : ''" th:text="#{home.rotate.title}"></a></li>
|
<li class="nav-item"><a class="nav-link" href="#" th:href="@{rotate-pdf}" th:classappend="${currentPage}=='rotate-pdf' ? 'active' : ''" th:text="#{home.rotate.title}"></a></li>
|
||||||
|
|
||||||
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='file-to-pdf' OR ${currentPage}=='xlsx-to-pdf' ? 'active' : ''"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
|
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='pdf-to-pdfa' OR ${currentPage}=='file-to-pdf' OR ${currentPage}=='xlsx-to-pdf' ? 'active' : ''"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
|
||||||
aria-haspopup="true" aria-expanded="false" th:text="#{navbar.convert}"></a>
|
aria-haspopup="true" aria-expanded="false" th:text="#{navbar.convert}"></a>
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<a class="dropdown-item" href="#" th:href="@{pdf-to-img}" th:classappend="${currentPage}=='pdf-to-img' ? 'active' : ''" th:text="#{home.pdfToImage.title}"></a>
|
<a class="dropdown-item" href="#" th:href="@{pdf-to-img}" th:classappend="${currentPage}=='pdf-to-img' ? 'active' : ''" th:text="#{home.pdfToImage.title}"></a>
|
||||||
<a class="dropdown-item" href="#" th:href="@{img-to-pdf}" th:classappend="${currentPage}=='img-to-pdf' ? 'active' : ''" th:text="#{home.imageToPdf.title}"></a>
|
<a class="dropdown-item" href="#" th:href="@{img-to-pdf}" th:classappend="${currentPage}=='img-to-pdf' ? 'active' : ''" th:text="#{home.imageToPdf.title}"></a>
|
||||||
<a class="dropdown-item" href="#" th:href="@{file-to-pdf}" th:classappend="${currentPage}=='file-to-pdf' ? 'active' : ''" th:text="#{home.fileToPDF.title}"></a>
|
<a class="dropdown-item" href="#" th:href="@{file-to-pdf}" th:classappend="${currentPage}=='file-to-pdf' ? 'active' : ''" th:text="#{home.fileToPDF.title}"></a>
|
||||||
|
<a class="dropdown-item" href="#" th:href="@{pdf-to-pdfa}" th:classappend="${currentPage}=='pdf-to-pdfa' ? 'active' : ''" th:text="#{home.pdfToPDFA.title}"></a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -172,8 +173,7 @@ function compareVersions(version1, version2) {
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="languageDropdown">
|
<div class="dropdown-menu" aria-labelledby="languageDropdown">
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_US">English (US)</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_GB">English</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_GB">English (UK)</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="ar_AR">العربية</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="ar_AR">العربية</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="de_DE">Deutsch</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="de_DE">Deutsch</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="fr_FR">Français</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="fr_FR">Français</a>
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
<!-- Jumbotron -->
|
<!-- Jumbotron -->
|
||||||
<div class="jumbotron jumbotron-fluid" id="jumbotron">
|
<div class="jumbotron jumbotron-fluid" id="jumbotron">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="display-4">Stirling PDF</h1>
|
<h1 class="display-4" th:text="${@appName}"></h1>
|
||||||
<p class="lead" th:text="#{home.desc}"></p>
|
<p class="lead" th:text="${@homeText != 'null' and @homeText != null and @homeText != ''} ? ${@homeText} : #{home.desc}"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -64,6 +64,7 @@
|
|||||||
|
|
||||||
<div th:replace="~{fragments/card :: card(cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf')}"></div>
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf')}"></div>
|
||||||
<div th:replace="~{fragments/card :: card(cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images')}"></div>
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images')}"></div>
|
||||||
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa')}"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<ul id="selectedFiles" class="list-group"></ul>
|
<ul id="selectedFiles" class="list-group"></ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group text-center">
|
<div class="form-group text-center">
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{merge.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{merge.submit}"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -19,18 +19,43 @@
|
|||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
|
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
|
||||||
|
<hr>
|
||||||
<div id="languages">
|
<div id="languages">
|
||||||
<div th:each="language: ${languages}">
|
<div th:each="language, iterStat : ${languages}" >
|
||||||
<input type="checkbox" class="form-check-input" th:name="languages" th:value="${language}" th:id="${'language-' + language}" />
|
<input type="checkbox" class="form-check-input" th:name="languages" th:value="${language}" th:id="${'language-' + language}" />
|
||||||
<label class="form-check-label" th:for="${'language-' + language}" th:text=" ${language}"></label>
|
<label class="form-check-label" th:for="${'language-' + language}" th:text=" ${language}"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="form-group">
|
<div class="form-group">
|
||||||
|
<label th:text="#{ocr.selectText.10}"></label>
|
||||||
|
<select class="form-control" name="ocrType">
|
||||||
|
<option value="skip-text" th:text="#{ocr.selectText.6}"></option>
|
||||||
|
<option value="force-ocr" th:text="#{ocr.selectText.7}"></option>
|
||||||
|
<option value="Normal" th:text="#{ocr.selectText.8}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<label for="languages" class="form-label" th:text="#{ocr.selectText.9}"></label>
|
||||||
|
<div class="form-check">
|
||||||
<input type="checkbox" class="form-check-input" name="sidecar" id="sidecar" />
|
<input type="checkbox" class="form-check-input" name="sidecar" id="sidecar" />
|
||||||
<label class="form-check-label" for="sidecar" th:text="#{ocr.selectText.2}"></label>
|
<label class="form-check-label" for="sidecar" th:text="#{ocr.selectText.2}"></label>
|
||||||
</div> -->
|
</div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{ocr.submit}"></button>
|
<div class="form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" name="deskew" id="deskew" />
|
||||||
|
<label class="form-check-label" for="deskew" th:text="#{ocr.selectText.3}"></label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" name="clean" id="clean" />
|
||||||
|
<label class="form-check-label" for="clean" th:text="#{ocr.selectText.4}"></label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" name="clean-final" id="clean-final" />
|
||||||
|
<label class="form-check-label" for="clean-final" th:text="#{ocr.selectText.5}"></label>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{ocr.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<p th:text="#{ocr.credit}"></p>
|
<p th:text="#{ocr.credit}"></p>
|
||||||
<p th:text="#{ocr.help}"></p>
|
<p th:text="#{ocr.help}"></p>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||||
<input type="text" class="form-control" id="fileInput" name="pageOrder" placeholder="(e.g. 1,3,2 or 4-8,2,10-12)" required>
|
<input type="text" class="form-control" id="fileInput" name="pageOrder" placeholder="(e.g. 1,3,2 or 4-8,2,10-12)" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{pdfOrganiser.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfOrganiser.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<label for="pagesToDelete" th:text="#{pageRemover.pagesToDelete}"></label>
|
<label for="pagesToDelete" th:text="#{pageRemover.pagesToDelete}"></label>
|
||||||
<input type="text" class="form-control" id="fileInput" name="pagesToDelete" placeholder="(e.g. 1,2,6 or 1-10,15-30)" required>
|
<input type="text" class="form-control" id="fileInput" name="pagesToDelete" placeholder="(e.g. 1,2,6 or 1-10,15-30)" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
|
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{rotate.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{rotate.submit}"></button>
|
||||||
<button type="button" class="btn btn-secondary" onclick="rotate(90)">
|
<button type="button" class="btn btn-secondary" onclick="rotate(90)">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
|
||||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
|
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div class="form-group text-center">
|
<div class="form-group text-center">
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{addPassword.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{addPassword.submit}"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
<input type="text" id="heightSpacer" name="heightSpacer" class="form-control" value="50" />
|
<input type="text" id="heightSpacer" name="heightSpacer" class="form-control" value="50" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group text-center">
|
<div class="form-group text-center">
|
||||||
<input type="submit" th:value="#{watermark.submit}" class="btn btn-primary" />
|
<input type="submit" id="submitBtn" th:value="#{watermark.submit}" class="btn btn-primary" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
<button type="button" class="btn btn-secondary" id="addMetadataBtn" th:text="#{changeMetadata.selectText.5}"></button>
|
<button type="button" class="btn btn-secondary" id="addMetadataBtn" th:text="#{changeMetadata.selectText.5}"></button>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<button class="btn btn-primary" type="submit" th:text="#{changeMetadata.submit}"></button>
|
<button class="btn btn-primary" type="submit" id="submitBtn" th:text="#{changeMetadata.submit}"></button>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const deleteAllCheckbox = document.querySelector("#deleteAll");
|
const deleteAllCheckbox = document.querySelector("#deleteAll");
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div class="form-group text-center">
|
<div class="form-group text-center">
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{permissions.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{permissions.submit}"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div class="form-group text-center">
|
<div class="form-group text-center">
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{removePassword.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removePassword.submit}"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<input type="text" id="watermarkText" name="watermarkText" class="form-control" placeholder="Stirling-PDF" required />
|
<input type="text" id="watermarkText" name="watermarkText" class="form-control" placeholder="Stirling-PDF" required />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group text-center">
|
<div class="form-group text-center">
|
||||||
<input type="submit" th:value="#{remove-watermark.submit}" class="btn btn-primary" />
|
<input type="submit" id="submitBtn" th:value="#{remove-watermark.submit}" class="btn btn-primary" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<input type="text" class="form-control" id="pages" name="pages" placeholder="1,3,5-10" required>
|
<input type="text" class="form-control" id="pages" name="pages" placeholder="1,3,5-10" required>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{split.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{split.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user