Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a7517ecdd | ||
|
|
03febd9484 | ||
|
|
655b97bfd5 | ||
|
|
fdbc7f4621 | ||
|
|
f9fe303671 |
44
Dockerfile
44
Dockerfile
@@ -1,47 +1,5 @@
|
|||||||
# Build jbig2enc in a separate stage
|
# Build jbig2enc in a separate stage
|
||||||
FROM debian:bullseye-slim as jbig2enc_builder
|
FROM frooodle/stirling-pdf-base:latest
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
git \
|
|
||||||
automake \
|
|
||||||
autoconf \
|
|
||||||
libtool \
|
|
||||||
libleptonica-dev \
|
|
||||||
pkg-config \
|
|
||||||
ca-certificates \
|
|
||||||
zlib1g-dev \
|
|
||||||
make \
|
|
||||||
g++
|
|
||||||
|
|
||||||
RUN git clone https://github.com/agl/jbig2enc && \
|
|
||||||
cd jbig2enc && \
|
|
||||||
./autogen.sh && \
|
|
||||||
./configure && \
|
|
||||||
make && \
|
|
||||||
make install
|
|
||||||
|
|
||||||
# Main stage
|
|
||||||
FROM openjdk:17-jdk-slim
|
|
||||||
|
|
||||||
# Install necessary dependencies
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
libreoffice-core \
|
|
||||||
libreoffice-common \
|
|
||||||
libreoffice-writer \
|
|
||||||
libreoffice-calc \
|
|
||||||
libreoffice-impress \
|
|
||||||
python3-uno \
|
|
||||||
python3-pip \
|
|
||||||
unoconv \
|
|
||||||
pngquant \
|
|
||||||
unpaper \
|
|
||||||
ocrmypdf && \
|
|
||||||
pip install --user --upgrade ocrmypdf
|
|
||||||
|
|
||||||
# Copy the jbig2enc binary from the builder stage
|
|
||||||
COPY --from=jbig2enc_builder /usr/local/bin/jbig2 /usr/local/bin/jbig2
|
|
||||||
|
|
||||||
# Copy the application JAR file
|
# Copy the application JAR file
|
||||||
COPY build/libs/*.jar app.jar
|
COPY build/libs/*.jar app.jar
|
||||||
|
|||||||
44
DockerfileBase
Normal file
44
DockerfileBase
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Build jbig2enc in a separate stage
|
||||||
|
FROM debian:bullseye-slim as jbig2enc_builder
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
git \
|
||||||
|
automake \
|
||||||
|
autoconf \
|
||||||
|
libtool \
|
||||||
|
libleptonica-dev \
|
||||||
|
pkg-config \
|
||||||
|
ca-certificates \
|
||||||
|
zlib1g-dev \
|
||||||
|
make \
|
||||||
|
g++
|
||||||
|
|
||||||
|
RUN git clone https://github.com/agl/jbig2enc && \
|
||||||
|
cd jbig2enc && \
|
||||||
|
./autogen.sh && \
|
||||||
|
./configure && \
|
||||||
|
make && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
# Main stage
|
||||||
|
FROM openjdk:17-jdk-slim
|
||||||
|
|
||||||
|
# Install necessary dependencies
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
libreoffice-core \
|
||||||
|
libreoffice-common \
|
||||||
|
libreoffice-writer \
|
||||||
|
libreoffice-calc \
|
||||||
|
libreoffice-impress \
|
||||||
|
python3-uno \
|
||||||
|
python3-pip \
|
||||||
|
unoconv \
|
||||||
|
pngquant \
|
||||||
|
unpaper \
|
||||||
|
ocrmypdf && \
|
||||||
|
pip install --user --upgrade ocrmypdf
|
||||||
|
|
||||||
|
# Copy the jbig2enc binary from the builder stage
|
||||||
|
COPY --from=jbig2enc_builder /usr/local/bin/jbig2 /usr/local/bin/jbig2
|
||||||
@@ -5,7 +5,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = 'stirling.software'
|
group = 'stirling.software'
|
||||||
version = '0.4.7'
|
version = '0.4.8'
|
||||||
sourceCompatibility = '17'
|
sourceCompatibility = '17'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@@ -21,7 +21,7 @@ dependencies {
|
|||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio
|
// https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio
|
||||||
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
|
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
|
||||||
|
implementation 'commons-io:commons-io:2.11.0'
|
||||||
|
|
||||||
//general PDF
|
//general PDF
|
||||||
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
|
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -29,6 +30,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;
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
@Controller
|
@Controller
|
||||||
public class OCRController {
|
public class OCRController {
|
||||||
|
|
||||||
@@ -42,8 +44,6 @@ 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,
|
||||||
@@ -59,9 +59,19 @@ public class OCRController {
|
|||||||
throw new IOException("Please select at least one language.");
|
throw new IOException("Please select at least one language.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate and sanitize selected languages using regex
|
||||||
|
String languagePattern = "^[a-zA-Z]{3}$"; // Regex pattern for three-letter language codes
|
||||||
|
selectedLanguages = selectedLanguages.stream()
|
||||||
|
.filter(lang -> Pattern.matches(languagePattern, lang))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
||||||
|
if (selectedLanguages.isEmpty()) {
|
||||||
|
throw new IOException("None of the selected languages are valid.");
|
||||||
|
}
|
||||||
// Save the uploaded file to a temporary location
|
// Save the uploaded file to a temporary location
|
||||||
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
||||||
inputFile.transferTo(tempInputFile.toFile());
|
Files.copy(inputFile.getInputStream(), tempInputFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
// Prepare the output file path
|
// Prepare the output file path
|
||||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ public class OverlayImageController {
|
|||||||
|
|
||||||
@PostMapping("/add-image")
|
@PostMapping("/add-image")
|
||||||
public ResponseEntity<byte[]> overlayImage(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("fileInput2") MultipartFile imageFile, @RequestParam("x") float x,
|
public ResponseEntity<byte[]> overlayImage(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("fileInput2") MultipartFile imageFile, @RequestParam("x") float x,
|
||||||
@RequestParam("y") float y) {
|
@RequestParam("y") float y, @RequestParam("everyPage") boolean everyPage) {
|
||||||
try {
|
try {
|
||||||
byte[] pdfBytes = pdfFile.getBytes();
|
byte[] pdfBytes = pdfFile.getBytes();
|
||||||
byte[] imageBytes = imageFile.getBytes();
|
byte[] imageBytes = imageFile.getBytes();
|
||||||
byte[] result = PdfUtils.overlayImage(pdfBytes, imageBytes, x, y);
|
byte[] result = PdfUtils.overlayImage(pdfBytes, imageBytes, x, y, everyPage);
|
||||||
|
|
||||||
return PdfUtils.bytesToWebResponse(result, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
|
return PdfUtils.bytesToWebResponse(result, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package stirling.software.SPDF.controller.converters;
|
package stirling.software.SPDF.controller.converters;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
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;
|
||||||
@@ -14,7 +15,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
@Controller
|
@Controller
|
||||||
@@ -39,14 +40,20 @@ public class ConvertOfficeController {
|
|||||||
|
|
||||||
|
|
||||||
public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
|
public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
|
||||||
|
// Check for valid file extension
|
||||||
|
String originalFilename = inputFile.getOriginalFilename();
|
||||||
|
if (originalFilename == null || !isValidFileExtension(FilenameUtils.getExtension(originalFilename))) {
|
||||||
|
throw new IllegalArgumentException("Invalid file extension");
|
||||||
|
}
|
||||||
|
|
||||||
// Save the uploaded file to a temporary location
|
// Save the uploaded file to a temporary location
|
||||||
Path tempInputFile = Files.createTempFile("input_", "." + getFileExtension(inputFile.getOriginalFilename()));
|
Path tempInputFile = Files.createTempFile("input_", "." + FilenameUtils.getExtension(originalFilename));
|
||||||
inputFile.transferTo(tempInputFile.toFile());
|
Files.copy(inputFile.getInputStream(), tempInputFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
// Prepare the output file path
|
// Prepare the output file path
|
||||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
|
|
||||||
// Run the LibreOffice command
|
// Run the LibreOffice command
|
||||||
List<String> command = new ArrayList<>(Arrays.asList("unoconv", "-vvv",
|
List<String> command = new ArrayList<>(Arrays.asList("unoconv", "-vvv",
|
||||||
"-f",
|
"-f",
|
||||||
"pdf",
|
"pdf",
|
||||||
@@ -64,14 +71,8 @@ public byte[] convertToPdf(MultipartFile inputFile) throws IOException, Interrup
|
|||||||
|
|
||||||
return pdfBytes;
|
return pdfBytes;
|
||||||
}
|
}
|
||||||
|
private boolean isValidFileExtension(String fileExtension) {
|
||||||
|
String extensionPattern = "^(?i)[a-z0-9]{2,4}$";
|
||||||
|
return fileExtension.matches(extensionPattern);
|
||||||
private String getFileExtension(String fileName) {
|
|
||||||
int dotIndex = fileName.lastIndexOf('.');
|
|
||||||
if (dotIndex == -1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return fileName.substring(dotIndex + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,29 +188,36 @@ public class PdfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] overlayImage(byte[] pdfBytes, byte[] imageBytes, float x, float y) throws IOException {
|
public static byte[] overlayImage(byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage) throws IOException {
|
||||||
|
|
||||||
|
PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes));
|
||||||
|
|
||||||
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes))) {
|
|
||||||
// Get the first page of the PDF
|
// Get the first page of the PDF
|
||||||
PDPage page = document.getPage(0);
|
int pages = document.getNumberOfPages();
|
||||||
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true)) {
|
for (int i = 0; i < pages; i++) {
|
||||||
// Create an image object from the image bytes
|
PDPage page = document.getPage(i);
|
||||||
PDImageXObject image = PDImageXObject.createFromByteArray(document, imageBytes, "");
|
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true)) {
|
||||||
// Draw the image onto the page at the specified x and y coordinates
|
// Create an image object from the image bytes
|
||||||
contentStream.drawImage(image, x, y);
|
PDImageXObject image = PDImageXObject.createFromByteArray(document, imageBytes, "");
|
||||||
logger.info("Image successfully overlayed onto PDF");
|
// Draw the image onto the page at the specified x and y coordinates
|
||||||
|
contentStream.drawImage(image, x, y);
|
||||||
|
logger.info("Image successfully overlayed onto PDF");
|
||||||
|
if (everyPage == false && i == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Log an error message if there is an issue overlaying the image onto the PDF
|
||||||
|
logger.error("Error overlaying image onto PDF", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Create a ByteArrayOutputStream to save the PDF to
|
// Create a ByteArrayOutputStream to save the PDF to
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
document.save(baos);
|
document.save(baos);
|
||||||
logger.info("PDF successfully saved to byte array");
|
logger.info("PDF successfully saved to byte array");
|
||||||
return baos.toByteArray();
|
return baos.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
// Log an error message if there is an issue overlaying the image onto the PDF
|
|
||||||
logger.error("Error overlaying image onto PDF", e);
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseEntity<byte[]> iTextDocToWebResponse(Document document, String docName) throws IOException, DocumentException {
|
public static ResponseEntity<byte[]> iTextDocToWebResponse(Document document, String docName) throws IOException, DocumentException {
|
||||||
// Close the document
|
// Close the document
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ fileToPDF.submit=\u062A\u062D\u0648\u064A\u0644 \u0625\u0644\u0649 PDF
|
|||||||
#Add image
|
#Add image
|
||||||
addImage.title=إضافة صورة
|
addImage.title=إضافة صورة
|
||||||
addImage.header=إضافة صورة إلى PDF (العمل قيد التقدم)
|
addImage.header=إضافة صورة إلى PDF (العمل قيد التقدم)
|
||||||
|
addImage.everyPage=كل صفحة؟
|
||||||
addImage.submit=إضافة صورة
|
addImage.submit=إضافة صورة
|
||||||
|
|
||||||
#compress
|
#compress
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ fileToPDF.submit=In PDF konvertieren
|
|||||||
#Add image
|
#Add image
|
||||||
addImage.title=Bild hinzufügen
|
addImage.title=Bild hinzufügen
|
||||||
addImage.header=Ein Bild einfügen (Work in progress)
|
addImage.header=Ein Bild einfügen (Work in progress)
|
||||||
|
addImage.everyPage=Jede Seite?
|
||||||
addImage.submit=Bild hinzufügen
|
addImage.submit=Bild hinzufügen
|
||||||
|
|
||||||
#compress
|
#compress
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ compress.submit=Compress
|
|||||||
#Add image
|
#Add image
|
||||||
addImage.title=Add Image
|
addImage.title=Add Image
|
||||||
addImage.header=Add image to PDF (Work in progress)
|
addImage.header=Add image to PDF (Work in progress)
|
||||||
|
addImage.everyPage=Every Page?
|
||||||
addImage.submit=Add image
|
addImage.submit=Add image
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
309
src/main/resources/messages_es_ES.properties
Normal file
309
src/main/resources/messages_es_ES.properties
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
###########
|
||||||
|
# Generic #
|
||||||
|
###########
|
||||||
|
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||||
|
language.direction=ltr
|
||||||
|
|
||||||
|
pdfPrompt=Selecciona PDF(s)
|
||||||
|
multiPdfPrompt=Selecciona PDFs (2+)
|
||||||
|
multiPdfDropPrompt=Selecciona (o arrastra y suelta) todos los PDFs que quieras
|
||||||
|
imgPrompt=Selecciona Imagen(es)
|
||||||
|
genericSubmit=Enviar
|
||||||
|
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
|
||||||
|
pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma):
|
||||||
|
goToPage=Ir
|
||||||
|
true=Verdadero
|
||||||
|
false=Falso
|
||||||
|
unknown=Desconocido
|
||||||
|
save=Guardar
|
||||||
|
close=Cerrar
|
||||||
|
|
||||||
|
#############
|
||||||
|
# HOME-PAGE #
|
||||||
|
#############
|
||||||
|
home.desc=Tu autohospedada ventanilla única para todas tus necesidades PDF.
|
||||||
|
|
||||||
|
navbar.convert=Convertir
|
||||||
|
navbar.security=Seguridad
|
||||||
|
navbar.other=Otro
|
||||||
|
navbar.darkmode=Modo oscuro
|
||||||
|
|
||||||
|
home.merge.title=Une PDFs
|
||||||
|
home.merge.desc=Unir fácilmente múltiples PDFs en uno.
|
||||||
|
|
||||||
|
home.split.title=Divide PDFs
|
||||||
|
home.split.desc=Divide PDFs en múltiples documentos
|
||||||
|
|
||||||
|
home.rotate.title=Rota PDFs
|
||||||
|
home.rotate.desc=Rota fácilmente tus PDFs.
|
||||||
|
|
||||||
|
home.imageToPdf.title=Imagen a PDF
|
||||||
|
home.imageToPdf.desc=Convierte una imagen (PNG, JPEG, GIF) a PDF.
|
||||||
|
|
||||||
|
home.pdfToImage.title=PDF a Imagen
|
||||||
|
home.pdfToImage.desc=Convierte un PDF a una imagen. (PNG, JPEG, GIF)
|
||||||
|
|
||||||
|
home.pdfOrganiser.title=Organizador PDF
|
||||||
|
home.pdfOrganiser.desc=Elimina/Reorganiza páginas en cualquier orden
|
||||||
|
|
||||||
|
home.addImage.title=Agregar imagen al PDF
|
||||||
|
home.addImage.desc=Agrega una imagen en una ubicación establecida en el PDF (trabajo en progreso)
|
||||||
|
|
||||||
|
home.watermark.title=Añade marca de agua
|
||||||
|
home.watermark.desc=Añade una marca de agua predefinida a tu documento PDF.
|
||||||
|
|
||||||
|
home.remove-watermark.title=Elimina marca de agua
|
||||||
|
home.remove-watermark.desc=Elimina marcas de agua de tu documento PDF.
|
||||||
|
|
||||||
|
home.permissions.title=Cambia Permisos
|
||||||
|
home.permissions.desc=Cambia los permisos de tu documento PDF
|
||||||
|
|
||||||
|
home.removePages.title=Elimina Páginas
|
||||||
|
home.removePages.desc=Elimina páginas no deseadas de tu documento PDF.
|
||||||
|
|
||||||
|
home.addPassword.title=Añade Contraseña
|
||||||
|
home.addPassword.desc=Encripta tu documento PDF con una contraseña.
|
||||||
|
|
||||||
|
home.removePassword.title=Elimina Contraseña
|
||||||
|
home.removePassword.desc=Elimina la contraseña de tu documento PDF.
|
||||||
|
|
||||||
|
home.compressPdfs.title=Comprime PDFs
|
||||||
|
home.compressPdfs.desc=Comprime PDFs para reducir el tamaño del fichero.
|
||||||
|
|
||||||
|
home.changeMetadata.title=Cambia Metadatos
|
||||||
|
home.changeMetadata.desc=Cambia/Elimina/Añade metadatos a tu documento PDF.
|
||||||
|
|
||||||
|
home.fileToPDF.title=Convierte fichero a PDF
|
||||||
|
home.fileToPDF.desc=Convierte casi cualquier archivo a PDF (DOCX, PNG, XLS, PPT, TXT y más)
|
||||||
|
|
||||||
|
home.ocr.title=Ejecute OCR en PDF y/o escaneos de limpieza
|
||||||
|
home.ocr.desc=Escaneos de limpieza y detecta texto de imágenes dentro de un PDF y lo vuelve a agregar como texto.
|
||||||
|
|
||||||
|
home.extractImages.title=Extraer imágenes
|
||||||
|
home.extractImages.desc=Extrae todas las imágenes de un PDF y las guarda en zip
|
||||||
|
|
||||||
|
home.pdfToPDFA.title=Convierte PDF to PDF/A
|
||||||
|
home.pdfToPDFA.desc=Convierte PDF to PDF/A para almacenamiento a largo plazo
|
||||||
|
|
||||||
|
|
||||||
|
navbar.settings=Ajustes
|
||||||
|
settings.title=Ajustes
|
||||||
|
settings.update=Actualización disponible
|
||||||
|
settings.appVersion=Version de la aplicacion:
|
||||||
|
settings.downloadOption.title=Elija la opción de descarga (para descargas de un solo archivo sin zip):
|
||||||
|
settings.downloadOption.1=Abre en la misma ventana
|
||||||
|
settings.downloadOption.2=Abre en una nueva ventana
|
||||||
|
settings.downloadOption.3=Descarga el fichero
|
||||||
|
settings.zipThreshold=Ficheros Zip cuando excede el número de ficheros descargados
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#OCR
|
||||||
|
ocr.title=OCR / Escaneo de limpieza
|
||||||
|
ocr.header=Escaneos de limpieza / OCR (Reconocimiento óptico de caracteres)
|
||||||
|
ocr.SeleccionaText.1=Selecciona los idiomas que se detectarán en el PDF (Los enumerados son los detectados actualmente):
|
||||||
|
ocr.SeleccionaText.2=Produzca un archivo de texto que contenga texto OCR junto con el PDF editado con OCR
|
||||||
|
ocr.SeleccionaText.3=Corrija las páginas que se escanearon en un ángulo torcido girándolas nuevamente a su lugar
|
||||||
|
ocr.SeleccionaText.4=Limpie la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo. (Sin cambio de salida)
|
||||||
|
ocr.SeleccionaText.5=Limpie la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo, mantiene la limpieza en la salida.
|
||||||
|
ocr.SeleccionaText.6=Ignora las páginas que tienen texto interactivo, solo las páginas OCR que son imágenes
|
||||||
|
ocr.SeleccionaText.7=Fuerza OCR, OCR eliminará en cada página todo el texto original
|
||||||
|
ocr.SeleccionaText.8=Normal (Se producirá un error si el PDF contiene texto)
|
||||||
|
ocr.SeleccionaText.9=Ajustes Adicionales
|
||||||
|
ocr.SeleccionaText.10=Modo OCR
|
||||||
|
ocr.help=Lea esta documentación sobre cómo usar esto para otros idiomas y/o no usarlo en docker
|
||||||
|
ocr.credit=Este servicio utiliza OCRmyPDF y Tesseract para OCR.
|
||||||
|
ocr.submit=Procesa PDF con OCR
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extractImages.title=Extraer imágenes
|
||||||
|
extractImages.header=Extraer imágenes
|
||||||
|
extractImages.SeleccionaText=Selecciona el formato de imagen para convertir las imágenes extraídas
|
||||||
|
extractImages.submit=Extraer
|
||||||
|
|
||||||
|
|
||||||
|
#File to PDF
|
||||||
|
fileToPDF.title=Fichero a PDF
|
||||||
|
fileToPDF.header=Convierte cualquier fichero a PDF
|
||||||
|
fileToPDF.credit=Este servicio usa LibreOffice y Unoconv para la conversión de ficheros.
|
||||||
|
fileToPDF.supportedFileTypes=Los tipos de ficheros soportados deben incluir los de abajo sin embargo para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice
|
||||||
|
fileToPDF.submit=Convertir a PDF
|
||||||
|
|
||||||
|
|
||||||
|
#compress
|
||||||
|
compress.title=Comprimir
|
||||||
|
compress.header=Comprimir PDF
|
||||||
|
compress.credit=Este servicio usa OCRmyPDF para la Compresión/Optimizatión del PDF.
|
||||||
|
compress.SeleccionaText.1=Nivel de Optimización:
|
||||||
|
compress.SeleccionaText.2=0 (Sin optimización)
|
||||||
|
compress.SeleccionaText.3=1 (Por defecto, optimización sin pérdidas)
|
||||||
|
compress.SeleccionaText.4=2 (Optimización con pérdida)
|
||||||
|
compress.SeleccionaText.5=3 (Optimización con pérdida, más agresiva)
|
||||||
|
compress.SeleccionaText.6=Habilita la vista web rápida (linealizar PDF)
|
||||||
|
compress.SeleccionaText.7=Habilita la codificación JBIG2 con pérdida
|
||||||
|
compress.submit=Comprimir
|
||||||
|
|
||||||
|
|
||||||
|
#Add image
|
||||||
|
addImage.title=Añade Imagen
|
||||||
|
addImage.header=Añade image de PDF (Trabajo en progreso)
|
||||||
|
addImage.everyPage=¿Todas las páginas?
|
||||||
|
addImage.submit=Añade imagen
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
merge.title=Mezcla
|
||||||
|
merge.header=Mezcla múltiples PDFs (2+)
|
||||||
|
merge.submit=Mezcla
|
||||||
|
|
||||||
|
#pdfOrganiser
|
||||||
|
pdfOrganiser.title=Organizador de páginas
|
||||||
|
pdfOrganiser.header=Organizador de páginas PDF
|
||||||
|
pdfOrganiser.submit=Organiza páginas
|
||||||
|
|
||||||
|
|
||||||
|
#pageRemover
|
||||||
|
pageRemover.title=Eliminador de páginas
|
||||||
|
pageRemover.header=Eliminador de páginas PDF
|
||||||
|
pageRemover.pagesToDelete=Páginas a eliminar (Introduzca una lista de números de página separados por coma):
|
||||||
|
pageRemover.submit=Elimina Páginas
|
||||||
|
|
||||||
|
#rotate
|
||||||
|
rotate.title=Rotar PDF
|
||||||
|
rotate.header=Rotar PDF
|
||||||
|
rotate.SeleccionaAngle=Selecciona ángulo de rotación (múltiple de 90 grados):
|
||||||
|
rotate.submit=Rotar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
split.title=Dividir PDF
|
||||||
|
split.header=Dividir PDF
|
||||||
|
split.desc.1=Los números que selecciona son el número de página en el que desea hacer una división
|
||||||
|
split.desc.2=Como tal, seleccionar 1,3,7-8 dividiría un documento de 10 páginas en 6 archivos PDF separados con:
|
||||||
|
split.desc.3=Documento #1: Page 1
|
||||||
|
split.desc.4=Documento #2: Page 2 and 3
|
||||||
|
split.desc.5=Documento #3: Page 4, 5 and 6
|
||||||
|
split.desc.6=Documento #4: Page 7
|
||||||
|
split.desc.7=Documento #5: Page 8
|
||||||
|
split.desc.8=Documento #6: Page 9 and 10
|
||||||
|
split.splitPages=Introduzca las páginas para dividir en:
|
||||||
|
split.submit=Dividir
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
imageToPDF.title=Imagen a PDF
|
||||||
|
imageToPDF.header=Imagen a PDF
|
||||||
|
imageToPDF.submit=Convertir
|
||||||
|
imageToPDF.SeleccionaText.1=Estirar para ajustar
|
||||||
|
imageToPDF.SeleccionaText.2=Auto rotación PDF
|
||||||
|
imageToPDF.SeleccionaText.3=Lógica de archivos múltiples (Únicamente activado si funciona con multiples imágenes)
|
||||||
|
imageToPDF.SeleccionaText.4=Une en un único PDF
|
||||||
|
imageToPDF.SeleccionaText.5=Convertir a PDFs separados
|
||||||
|
|
||||||
|
#pdfToImage
|
||||||
|
pdfToImage.title=PDF a Imagen
|
||||||
|
pdfToImage.header=PDF a Imagen
|
||||||
|
pdfToImage.SeleccionaText=Formato de Imagen
|
||||||
|
pdfToImage.singleOrMultiple=Tipo resultante de imagen
|
||||||
|
pdfToImage.single=Imagen Grande Única
|
||||||
|
pdfToImage.multi=Múltiples Imágenes
|
||||||
|
pdfToImage.colorType=Tipo de color
|
||||||
|
pdfToImage.color=Color
|
||||||
|
pdfToImage.grey=Escala de Grises
|
||||||
|
pdfToImage.blackwhite=Blanco y Negro (¡Puedes perder datos!)
|
||||||
|
pdfToImage.submit=Convertir
|
||||||
|
|
||||||
|
#addPassword
|
||||||
|
addPassword.title=Añade Contraseña
|
||||||
|
addPassword.header=Añade contraseña (Encripta)
|
||||||
|
addPassword.SeleccionaText.1=Selecciona PDF para encriptar
|
||||||
|
addPassword.SeleccionaText.2=Contraseña
|
||||||
|
addPassword.SeleccionaText.3=Longitud de la clave de cifrado
|
||||||
|
addPassword.SeleccionaText.4=Valores altos son más fuertes, pero valores bajos tienen mejor compatibilidad.
|
||||||
|
addPassword.SeleccionaText.5=Permisos para establecer
|
||||||
|
addPassword.SeleccionaText.6=Impedir el ensamblaje del documento
|
||||||
|
addPassword.SeleccionaText.7=Impedir la extracción de contenido
|
||||||
|
addPassword.SeleccionaText.8=Impedir la extracción para la accesibilidad
|
||||||
|
addPassword.SeleccionaText.9=Impedir rellenar formulario
|
||||||
|
addPassword.SeleccionaText.10=Impedir modificación
|
||||||
|
addPassword.SeleccionaText.11=Impedir modificación de anotaciones
|
||||||
|
addPassword.SeleccionaText.12=Impedir imprimir
|
||||||
|
addPassword.SeleccionaText.13=Impedir imprimir diferentes formatos
|
||||||
|
addPassword.submit=Encripta
|
||||||
|
|
||||||
|
#watermark
|
||||||
|
watermark.title=Añade marca de agua
|
||||||
|
watermark.header=Añade marca de agua
|
||||||
|
watermark.SeleccionaText.1=Selecciona PDF para añadir marca de agua:
|
||||||
|
watermark.SeleccionaText.2=Texto de la marca de agua:
|
||||||
|
watermark.SeleccionaText.3=Tamaño de la Fuente:
|
||||||
|
watermark.SeleccionaText.4=Rotación (0-360):
|
||||||
|
watermark.SeleccionaText.5=Ancho (Espacio entre cada marca de agua horizontalmente):
|
||||||
|
watermark.SeleccionaText.6=Alto (Espacio entre cada marca de agua verticalmente):
|
||||||
|
watermark.SeleccionaText.7=Opacidad (0% - 100%):
|
||||||
|
watermark.submit=Añade marca de agua
|
||||||
|
|
||||||
|
#remove-watermark
|
||||||
|
remove-watermark.title=Elimina marca de agua
|
||||||
|
remove-watermark.header=Elimina marca de agua
|
||||||
|
remove-watermark.SeleccionaText.1=Selecciona PDF para eliminar la marca de agua:
|
||||||
|
remove-watermark.SeleccionaText.2=Texto de la marca de agua:
|
||||||
|
remove-watermark.submit=Elimina marca de agua
|
||||||
|
|
||||||
|
#Change permissions
|
||||||
|
permissions.title=Cambiar Permisos
|
||||||
|
permissions.header=Cambiar Permisos
|
||||||
|
permissions.warning=Advertencia para que estos permisos no se puedan cambiar, se recomienda configurarlos con una contraseña a través de la página de cambio de contraseña
|
||||||
|
permissions.SeleccionaText.1=Selecciona PDF para cambiar los permisos
|
||||||
|
permissions.SeleccionaText.2=Permisos a establecer
|
||||||
|
permissions.SeleccionaText.3=Impedir el ensamblaje del documento
|
||||||
|
permissions.SeleccionaText.4=Impedir la extracción de contenido
|
||||||
|
permissions.SeleccionaText.5=Impedir la extracción para la accesibilidad
|
||||||
|
permissions.SeleccionaText.6=Impedir rellenar formulario
|
||||||
|
permissions.SeleccionaText.7=Impedir modificación
|
||||||
|
permissions.SeleccionaText.8=Impedir modificación de anotaciones
|
||||||
|
permissions.SeleccionaText.9=Impedir imprimir
|
||||||
|
permissions.SeleccionaText.10=Impedir imprimir diferentes formatos
|
||||||
|
permissions.submit=Cambiar
|
||||||
|
|
||||||
|
#remove password
|
||||||
|
removePassword.title=Elimina contraseña
|
||||||
|
removePassword.header=Elimina contraseña (Desencripta)
|
||||||
|
removePassword.SeleccionaText.1=Selecciona PDF para Desencriptar
|
||||||
|
removePassword.SeleccionaText.2=Contraseña
|
||||||
|
removePassword.submit=Elimina
|
||||||
|
|
||||||
|
changeMetadata.title=Cambia Metadatos
|
||||||
|
changeMetadata.header=Cambia Metadatos
|
||||||
|
changeMetadata.SeleccionaText.1=Edite las variables que desea cambiar
|
||||||
|
changeMetadata.SeleccionaText.2=Elimina todos los metadatos
|
||||||
|
changeMetadata.SeleccionaText.3=Mostrar metadatos personalizados:
|
||||||
|
changeMetadata.author=Autor:
|
||||||
|
changeMetadata.creationDate=Fecha de Creación (yyyy/MM/dd HH:mm:ss):
|
||||||
|
changeMetadata.creator=Creador:
|
||||||
|
changeMetadata.keywords=Palabras clave:
|
||||||
|
changeMetadata.modDate=Fecha de Modificación (yyyy/MM/dd HH:mm:ss):
|
||||||
|
changeMetadata.producer=Productor:
|
||||||
|
changeMetadata.subject=Asunto:
|
||||||
|
changeMetadata.title=Título:
|
||||||
|
changeMetadata.trapped=Trapped:
|
||||||
|
changeMetadata.SeleccionaText.4=Otros Metadatos:
|
||||||
|
changeMetadata.SeleccionaText.5=Agregar entrada de metadatos personalizados
|
||||||
|
changeMetadata.submit=Cambia
|
||||||
|
|
||||||
|
xlsToPdf.title=Excel a PDF
|
||||||
|
xlsToPdf.header=Excel a PDF
|
||||||
|
xlsToPdf.SeleccionaText.1=Selecciona hoja de cálculo de Excel XLS o XLSX para convertir
|
||||||
|
xlsToPdf.convert=convertir
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pdfToPDFA.title=PDF a PDF/A
|
||||||
|
pdfToPDFA.header=PDF a PDF/A
|
||||||
|
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
|
||||||
|
pdfToPDFA.submit=Convertir
|
||||||
@@ -137,6 +137,7 @@ fileToPDF.submit=Convertir en PDF
|
|||||||
#Add image
|
#Add image
|
||||||
addImage.title=Ajouter une image
|
addImage.title=Ajouter une image
|
||||||
addImage.header=Ajouter une image au PDF (Travail en cours)
|
addImage.header=Ajouter une image au PDF (Travail en cours)
|
||||||
|
addImage.everyPage=Chaque page?
|
||||||
addImage.submit=Ajouter une image
|
addImage.submit=Ajouter une image
|
||||||
|
|
||||||
#compress
|
#compress
|
||||||
|
|||||||
@@ -24,3 +24,4 @@ body {
|
|||||||
#support-section {
|
#support-section {
|
||||||
background-color: #444 !important;
|
background-color: #444 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
<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>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="checkbox" id="everyPage" name="everyPage" value="true"> <label for="everyPage" th:text="#{addImage.everyPage}"></label>
|
||||||
|
</div>
|
||||||
<button type="submit" id="submitBtn" 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>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<div th:fragment="card" class="feature-card">
|
<div th:fragment="card" class="feature-card">
|
||||||
<h5 class="card-title" th:text="${cardTitle}"></h5>
|
<a th:href="${cardLink}">
|
||||||
<p class="card-text" th:text="${cardText}"></p>
|
<h5 class="card-title text-primary" th:text="${cardTitle}"></h5>
|
||||||
<a class="btn btn-primary" th:href="${cardLink}" th:text="#{goToPage}"></a>
|
<p class="card-text" th:text="${cardText}"></p>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -146,6 +146,7 @@ function compareVersions(version1, version2) {
|
|||||||
<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>
|
||||||
|
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="es_ES" >Spanish</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|||||||
@@ -6,22 +6,46 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.features-container {
|
.features-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
|
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
|
||||||
gap: 25px 30px;
|
gap: 25px 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature-card {
|
.feature-card {
|
||||||
border: 1px solid rgba(0, 0, 0, .125);
|
border: 2px solid rgba(0, 0, 0, .25);
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
background: rgba(13, 110, 253, 0.05);
|
||||||
|
transition: transform 0.3s, border 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature-card .card-text {
|
.feature-card .card-text {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card:hover {
|
||||||
|
border: 2px solid rgba(0, 0, 0, .5);
|
||||||
|
cursor: pointer;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card:hover .card-title {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.card-title.text-primary {
|
||||||
|
color: #013275; /* Replace with your desired shade of blue */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user