Compare commits

..

15 Commits

Author SHA1 Message Date
Anthony Stirling
e0f306d3f7 updates 2023-09-29 23:58:37 +01:00
Anthony Stirling
09db6618d6 Merge pull request #390 from JerronAB/main
Removed numpy library from detect-blank-pages.py
2023-09-29 21:24:29 +01:00
JerronAB
c5ea254945 Removed numpy library from blank page py script 2023-09-29 16:00:22 -04:00
Anthony Stirling
1fc1ecbaa6 Update remove-password.html
allow removal of encryption without password #383
2023-09-28 12:35:44 -05:00
Anthony Stirling
1e2eb9b07a additional fix to #364 2023-09-24 21:21:01 +01:00
Anthony Stirling
ece00956d9 fix for config #376 2023-09-24 21:09:34 +01:00
Anthony Stirling
af5bbd8838 Merge pull request #375 from slikie/patch-2
Docs Fix - Ensure proper context path format
2023-09-20 09:21:07 -05:00
slikie
3a8f2495ea fix: Docs - Ensure proper context path format 2023-09-20 22:12:47 +08:00
slikie
993f5e5097 Update README.md
spelling
2023-09-20 22:08:31 +08:00
Anthony Stirling
05ebf3a6b4 Merge pull request #366 from Frooodle/image
image to pdf change and cert atempt fix
2023-09-17 21:21:19 +01:00
Anthony Stirling
1be3046d26 version bump 2023-09-17 21:17:47 +01:00
Anthony Stirling
5b3858ba29 image changes and cert fix 2023-09-17 21:17:13 +01:00
Anthony Stirling
a1f388e524 Merge pull request #365 from NeilJared/main
Update messages_es_ES.properties
2023-09-17 08:04:52 +01:00
NeilJared
cf14ff1540 Update messages_es_ES.properties
Updated es_ES translation including changes of the latest version
2023-09-16 23:39:12 +02:00
Anthony Stirling
a0ac2bc02a Update build.gradle 2023-09-14 21:25:18 +01:00
37 changed files with 557 additions and 277 deletions

View File

@@ -12,21 +12,22 @@ RUN apt-get update && \
# Set Environment Variables
ENV PUID=1000 \
PGID=1000 \
UMASK=022 \
DOCKER_ENABLE_SECURITY=false \
ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG
VERSION_TAG=$VERSION_TAG
# PUID=1000 \
# PGID=1000 \
# UMASK=022 \
# Create user and group
RUN groupadd -g $PGID stirlingpdfgroup && \
useradd -u $PUID -g stirlingpdfgroup -s /bin/sh stirlingpdfuser && \
mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME
#RUN groupadd -g $PGID stirlingpdfgroup && \
# useradd -u $PUID -g stirlingpdfgroup -s /bin/sh stirlingpdfuser && \
# mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME
# Set up necessary directories and permissions
RUN mkdir -p /scripts /usr/share/fonts/opentype/noto /configs /customFiles && \
chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/fonts/opentype/noto /configs /customFiles
RUN mkdir -p /scripts /usr/share/fonts/opentype/noto /configs /customFiles
# chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/fonts/opentype/noto /configs /customFiles
# Copy necessary files
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
@@ -34,8 +35,8 @@ COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
COPY build/libs/*.jar app.jar
# Set font cache and permissions
RUN fc-cache -f -v && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
RUN fc-cache -f -v
# chown stirlingpdfuser:stirlingpdfgroup /app.jar
@@ -48,5 +49,6 @@ ENV ENDPOINTS_GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF
ENV DOCKER_ENABLE_SECURITY=false
# Run the application
USER stirlingpdfuser
#USER stirlingpdfuser
CMD ["java", "-jar", "/app.jar"]

View File

@@ -222,7 +222,7 @@ metrics:
- customStaticFilePath. Customise static files such as the app logo by placing files in the /customFiles/static/ directory. An example of customising app logo is placing a /customFiles/static/favicon.svg to override current SVG. This can be used to change any images/icons/css/fonts/js etc in Stirling-PDF
### Environment only parameters
- ``SYSTEM_ROOTURIPATH`` ie set to ``pdf-app`` to Set the application's root URI tp ``localhost:8080/pdf-app``
- ``SYSTEM_ROOTURIPATH`` ie set to ``/pdf-app`` to Set the application's root URI to ``localhost:8080/pdf-app``
- ``SYSTEM_CONNECTIONTIMEOUTMINUTES`` to set custom connection timeout values
- ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login)
@@ -235,7 +235,8 @@ For those wanting to use Stirling-PDFs backend API to link with their own custom
### Prerequisites:
- User must have the folder ./configs volumed within docker so that it is retained during updates.
- Docker uses must download the security jar version by setting ``DOCKER_ENABLE_SECURITY`` to ``true`` in environment variables.
- Now the initial user will be generated with username ``admin`` and password ``stirling``. On login you will be forced to change the password to a new one.
- Then either enable login via the settings.yml file or via setting ``SECURITY_ENABLE_LOGIN`` to ``true``
- Now the initial user will be generated with username ``admin`` and password ``stirling``. On login you will be forced to change the password to a new one. You can also use the environment variables ``SECURITY_INITIALLOGIN_USERNAME`` and ``SECURITY_INITIALLOGIN_PASSWORD`` to set your own straight away (Recommended to remove them after user creation).
Once the above has been done, on restart, a new stirling-pdf-DB.mv.db will show if everything worked.
@@ -261,4 +262,7 @@ For API usage you must provide a header with 'X-API-Key' and the associated API
- Fill forms mannual and automatic
### Q2: Why is my application downloading .htm files?
This is a issue caused commonly by your NGINX congifuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. client_max_body_size SIZE; Where "SIZE" is 50M for example for 50MB files.
This is a issue caused commonly by your NGINX congifuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. ``client_max_body_size SIZE;`` Where "SIZE" is 50M for example for 50MB files.
### Q3: Why is my download timing out
NGINX has timeout values by default so if you are running Stirling-PDF behind NGINX you may need to set a timeout value such as adding the config ``proxy_read_timeout 3600;``

View File

@@ -8,7 +8,7 @@ plugins {
}
group = 'stirling.software'
version = '0.14.1'
version = '0.14.4'
sourceCompatibility = '17'
repositories {
@@ -34,7 +34,7 @@ sourceSets {
openApi {
apiDocsUrl = "http://localhost:8080/v3/api-docs"
apiDocsUrl = "http://localhost:8080/v1/api-docs"
outputDir = file("$projectDir")
outputFileName = "SwaggerDoc.json"
}

View File

@@ -1,5 +1,4 @@
import cv2
import numpy as np
import sys
import argparse

View File

@@ -12,6 +12,8 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.context.ApplicationContextInitializer;
@@ -19,83 +21,109 @@ import org.springframework.context.ConfigurableApplicationContext;
public class ConfigInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {
ensureConfigExists();
} catch (IOException e) {
throw new RuntimeException("Failed to initialize application configuration", e);
}
}
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {
ensureConfigExists();
} catch (IOException e) {
throw new RuntimeException("Failed to initialize application configuration", e);
}
}
public void ensureConfigExists() throws IOException {
// Define the path to the external config directory
Path destPath = Paths.get("configs", "settings.yml");
public void ensureConfigExists() throws IOException {
// Define the path to the external config directory
Path destPath = Paths.get("configs", "settings.yml");
// Check if the file already exists
if (Files.notExists(destPath)) {
// Ensure the destination directory exists
Files.createDirectories(destPath.getParent());
// Check if the file already exists
if (Files.notExists(destPath)) {
// Ensure the destination directory exists
Files.createDirectories(destPath.getParent());
// Copy the resource from classpath to the external directory
try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
if (in != null) {
Files.copy(in, destPath);
} else {
throw new FileNotFoundException("Resource file not found: settings.yml.template");
}
}
} else {
// If user file exists, we need to merge it with the template from the classpath
List<String> templateLines;
try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
templateLines = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)).lines().collect(Collectors.toList());
}
// Copy the resource from classpath to the external directory
try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
if (in != null) {
Files.copy(in, destPath);
} else {
throw new FileNotFoundException("Resource file not found: settings.yml.template");
}
}
} else {
// If user file exists, we need to merge it with the template from the classpath
List<String> templateLines;
try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
templateLines = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)).lines()
.collect(Collectors.toList());
}
mergeYamlFiles(templateLines, destPath, destPath);
}
}
mergeYamlFiles(templateLines, destPath, destPath);
}
}
public void mergeYamlFiles(List<String> templateLines, Path userFilePath, Path outputPath) throws IOException {
List<String> userLines = Files.readAllLines(userFilePath);
public void mergeYamlFiles(List<String> templateLines, Path userFilePath, Path outputPath) throws IOException {
List<String> userLines = Files.readAllLines(userFilePath);
List<String> mergedLines = new ArrayList<>();
boolean insideAutoGenerated = false;
boolean beforeFirstKey = true;
List<String> mergedLines = new ArrayList<>();
boolean insideAutoGenerated = false;
Function<String, Boolean> isCommented = line -> line.trim().startsWith("#");
Function<String, String> extractKey = line -> {
String[] parts = line.split(":");
return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : "";
};
for (String line : templateLines) {
// Check if we've entered or left the AutomaticallyGenerated section
if (line.trim().equalsIgnoreCase("AutomaticallyGenerated:")) {
insideAutoGenerated = true;
mergedLines.add(line);
continue;
} else if (insideAutoGenerated && line.trim().isEmpty()) {
// We have reached the end of the AutomaticallyGenerated section
insideAutoGenerated = false;
mergedLines.add(line);
continue;
}
Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet());
if (insideAutoGenerated) {
// Add lines from user's settings if we are inside AutomaticallyGenerated
Optional<String> userAutoGenValue = userLines.stream().filter(l -> l.trim().startsWith(line.split(":")[0].trim())).findFirst();
if (userAutoGenValue.isPresent()) {
mergedLines.add(userAutoGenValue.get());
continue;
}
} else {
// Outside of AutomaticallyGenerated, continue as before
if (line.contains(": ")) {
String key = line.split(": ")[0].trim();
Optional<String> userValue = userLines.stream().filter(l -> l.trim().startsWith(key)).findFirst();
if (userValue.isPresent()) {
mergedLines.add(userValue.get());
continue;
}
}
mergedLines.add(line);
}
}
for (String line : templateLines) {
String key = extractKey.apply(line);
if (line.trim().equalsIgnoreCase("AutomaticallyGenerated:")) {
insideAutoGenerated = true;
mergedLines.add(line);
continue;
} else if (insideAutoGenerated && line.trim().isEmpty()) {
insideAutoGenerated = false;
mergedLines.add(line);
continue;
}
if (beforeFirstKey && (isCommented.apply(line) || line.trim().isEmpty())) {
// Handle top comments and empty lines before the first key.
mergedLines.add(line);
continue;
}
if (!key.isEmpty())
beforeFirstKey = false;
if (userKeys.contains(key)) {
// If user has any version (commented or uncommented) of this key, skip the
// template line
Optional<String> userValue = userLines.stream()
.filter(l -> extractKey.apply(l).equalsIgnoreCase(key) && !isCommented.apply(l)).findFirst();
if (userValue.isPresent())
mergedLines.add(userValue.get());
continue;
}
if (isCommented.apply(line) || line.trim().isEmpty() || !userKeys.contains(key)) {
mergedLines.add(line); // If line is commented, empty or key not present in user's file, retain the
// template line
continue;
}
}
// Add any additional uncommented user lines that are not present in the
// template
for (String userLine : userLines) {
String userKey = extractKey.apply(userLine);
boolean isPresentInTemplate = templateLines.stream().map(extractKey)
.anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey));
if (!isPresentInTemplate && !isCommented.apply(userLine)) {
mergedLines.add(userLine);
}
}
Files.write(outputPath, mergedLines, StandardCharsets.UTF_8);
}
Files.write(outputPath, mergedLines, StandardCharsets.UTF_8);
}
}

View File

@@ -26,11 +26,18 @@ public class InitialSecuritySetup {
@PostConstruct
public void init() {
if (!userService.hasUsers()) {
String initialUsername = "admin";
String initialPassword = "stirling";
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId(), true);
String initialUsername = applicationProperties.getSecurity().getInitialLogin().getUsername();
String initialPassword = applicationProperties.getSecurity().getInitialLogin().getPassword();
if (initialUsername != null && initialPassword != null) {
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
} else {
initialUsername = "admin";
initialPassword = "stirling";
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId(), true);
}
}
}

View File

@@ -1,6 +1,7 @@
package stirling.software.SPDF.controller.api;
import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -42,7 +43,8 @@ public class MultiPageLayoutController {
int pagesPerSheet = request.getPagesPerSheet();
MultipartFile file = request.getFileInput();
boolean addBorder = request.isAddBorder();
if (pagesPerSheet != 2 && pagesPerSheet != 3 && pagesPerSheet != (int) Math.sqrt(pagesPerSheet) * Math.sqrt(pagesPerSheet)) {
throw new IllegalArgumentException("pagesPerSheet must be 2, 3 or a perfect square");
}
@@ -62,6 +64,10 @@ public class MultiPageLayoutController {
PDPageContentStream contentStream = new PDPageContentStream(newDocument, newPage, PDPageContentStream.AppendMode.APPEND, true, true);
LayerUtility layerUtility = new LayerUtility(newDocument);
float borderThickness = 1.5f; // Specify border thickness as required
contentStream.setLineWidth(borderThickness);
contentStream.setStrokingColor(Color.BLACK);
for (int i = 0; i < totalPages; i++) {
if (i != 0 && i % pagesPerSheet == 0) {
// Close the current content stream and create a new page and content stream
@@ -92,6 +98,14 @@ public class MultiPageLayoutController {
contentStream.drawForm(formXObject);
contentStream.restoreGraphicsState();
if(addBorder) {
// Draw border around each page
float borderX = colIndex * cellWidth;
float borderY = newPage.getMediaBox().getHeight() - (rowIndex + 1) * cellHeight;
contentStream.addRect(borderX, borderY, cellWidth, cellHeight);
contentStream.stroke();
}
}

View File

@@ -79,12 +79,12 @@ public class ConvertImgPDFController {
description = "This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images. Input:Image Output:PDF Type:SISO?")
public ResponseEntity<byte[]> convertToPdf(@ModelAttribute ConvertToPdfRequest request) throws IOException {
MultipartFile[] file = request.getFileInput();
boolean stretchToFit = request.isStretchToFit();
String fitOption = request.getFitOption();
String colorType = request.getColorType();
boolean autoRotate = request.isAutoRotate();
// Convert the file to PDF and get the resulting bytes
byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate, colorType);
byte[] bytes = PdfUtils.imageToPdf(file, fitOption, autoRotate, colorType);
return WebResponseUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_converted.pdf");
}

View File

@@ -1,5 +1,8 @@
package stirling.software.SPDF.controller.api.misc;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
@@ -58,7 +61,8 @@ public class ExtractImagesController {
int imageIndex = 1;
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
int pageNum = 1;
int pageNum = 0;
Set<Integer> processedImages = new HashSet<>();
// Iterate over each page
for (PDPage page : document.getPages()) {
++pageNum;
@@ -66,7 +70,12 @@ public class ExtractImagesController {
for (COSName name : page.getResources().getXObjectNames()) {
if (page.getResources().isImageXObject(name)) {
PDImageXObject image = (PDImageXObject) page.getResources().getXObject(name);
int imageHash = image.hashCode();
if(processedImages.contains(imageHash)) {
continue; // Skip already processed images
}
processedImages.add(imageHash);
// Convert image to desired format
RenderedImage renderedImage = image.getImage();
BufferedImage bufferedImage = null;

View File

@@ -12,6 +12,7 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
@@ -130,7 +131,8 @@ public class CertSignController {
signature.setName(name);
signature.setLocation(location);
signature.setReason(reason);
signature.setSignDate(Calendar.getInstance());
// Load the PDF
try (PDDocument document = PDDocument.load(pdf.getBytes())) {
logger.info("Successfully loaded the provided PDF");

View File

@@ -386,12 +386,16 @@ public class GetInfoOnPDF {
float width = mediaBox.getWidth();
float height = mediaBox.getHeight();
pageInfo.put("Width", width);
pageInfo.put("Height", height);
ObjectNode sizeInfo = objectMapper.createObjectNode();
getDimensionInfo(sizeInfo, width, height);
sizeInfo.put("Standard Page", getPageSize(width, height));
pageInfo.set("Size", sizeInfo);
pageInfo.put("Rotation", page.getRotation());
pageInfo.put("Page Orientation", getPageOrientation(width, height));
pageInfo.put("Standard Size", getPageSize(width, height));
// Boxes
pageInfo.put("MediaBox", mediaBox.toString());
@@ -620,7 +624,7 @@ public class GetInfoOnPDF {
pageInfoParent.set("Page " + pageNum, pageInfo);
pageInfoParent.set("Page " + (pageNum+1), pageInfo);
}
@@ -670,28 +674,52 @@ public class GetInfoOnPDF {
return "Square";
}
}
public String getPageSize(double width, double height) {
// Common aspect ratios used for standard paper sizes
double[] aspectRatios = {4.0 / 3.0, 3.0 / 2.0, Math.sqrt(2.0), 16.0 / 9.0};
public String getPageSize(float width, float height) {
// Define standard page sizes
Map<String, PDRectangle> standardSizes = new HashMap<>();
standardSizes.put("Letter", PDRectangle.LETTER);
standardSizes.put("LEGAL", PDRectangle.LEGAL);
standardSizes.put("A0", PDRectangle.A0);
standardSizes.put("A1", PDRectangle.A1);
standardSizes.put("A2", PDRectangle.A2);
standardSizes.put("A3", PDRectangle.A3);
standardSizes.put("A4", PDRectangle.A4);
standardSizes.put("A5", PDRectangle.A5);
standardSizes.put("A6", PDRectangle.A6);
// Check if the page matches any common aspect ratio
for (double aspectRatio : aspectRatios) {
if (isCloseToAspectRatio(width, height, aspectRatio)) {
return "Standard";
for (Map.Entry<String, PDRectangle> entry : standardSizes.entrySet()) {
PDRectangle size = entry.getValue();
if (isCloseToSize(width, height, size.getWidth(), size.getHeight())) {
return entry.getKey();
}
}
// If not a standard aspect ratio, consider it as a custom size
return "Custom";
}
private boolean isCloseToAspectRatio(double width, double height, double aspectRatio) {
// Calculate the aspect ratio of the page
double pageAspectRatio = width / height;
// Compare the page aspect ratio with the common aspect ratio within a threshold
return Math.abs(pageAspectRatio - aspectRatio) <= 0.05;
private boolean isCloseToSize(float width, float height, float standardWidth, float standardHeight) {
float tolerance = 1.0f; // You can adjust the tolerance as needed
return Math.abs(width - standardWidth) <= tolerance && Math.abs(height - standardHeight) <= tolerance;
}
public ObjectNode getDimensionInfo(ObjectNode dimensionInfo, float width, float height) {
float ppi = 72; // Points Per Inch
float widthInInches = width / ppi;
float heightInInches = height / ppi;
float widthInCm = widthInInches * 2.54f;
float heightInCm = heightInInches * 2.54f;
dimensionInfo.put("Width (px)", String.format("%.2f", width));
dimensionInfo.put("Height (px)", String.format("%.2f", height));
dimensionInfo.put("Width (in)", String.format("%.2f", widthInInches));
dimensionInfo.put("Height (in)", String.format("%.2f", heightInInches));
dimensionInfo.put("Width (cm)", String.format("%.2f", widthInCm));
dimensionInfo.put("Height (cm)", String.format("%.2f", heightInCm));
return dimensionInfo;
}
public static boolean checkForStandard(PDDocument document, String standardKeyword) {

View File

@@ -105,7 +105,16 @@ public class ApplicationProperties {
public static class Security {
private Boolean enableLogin;
private Boolean csrfDisabled;
private InitialLogin initialLogin;
public InitialLogin getInitialLogin() {
return initialLogin != null ? initialLogin : new InitialLogin();
}
public void setInitialLogin(InitialLogin initialLogin) {
this.initialLogin = initialLogin;
}
public Boolean getEnableLogin() {
return enableLogin;
}
@@ -125,9 +134,39 @@ public class ApplicationProperties {
@Override
public String toString() {
return "Security [enableLogin=" + enableLogin + ", csrfDisabled="
return "Security [enableLogin=" + enableLogin + ", initialLogin=" + initialLogin + ", csrfDisabled="
+ csrfDisabled + "]";
}
public static class InitialLogin {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "InitialLogin [username=" + username + ", password=" + (password != null && !password.isEmpty() ? "MASKED" : "NULL") + "]";
}
}
}
public static class System {

View File

@@ -13,8 +13,11 @@ public class ConvertToPdfRequest {
@Schema(description = "The input images to be converted to a PDF file")
private MultipartFile[] fileInput;
@Schema(description = "Whether to stretch the images to fit the PDF page or maintain the aspect ratio", example = "false")
private boolean stretchToFit;
@Schema(description = "Option to determine how the image will fit onto the page",
allowableValues = { "fillPage", "fitDocumentToImage", "maintainAspectRatio" })
private String fitOption;
@Schema(description = "The color type of the output image(s)", allowableValues = {"color", "greyscale", "blackwhite"})
private String colorType;

View File

@@ -12,4 +12,7 @@ public class MergeMultiplePagesRequest extends PDFFile {
@Schema(description = "The number of pages to fit onto a single sheet in the output PDF.",
type = "integer", allowableValues = {"2", "3", "4", "9", "16"})
private int pagesPerSheet;
@Schema(description = "Boolean for if you wish to add border around the pages")
private boolean addBorder;
}

View File

@@ -248,7 +248,7 @@ public class PdfUtils {
throw e;
}
}
public static byte[] imageToPdf(MultipartFile[] files, boolean stretchToFit, boolean autoRotate, String colorType) throws IOException {
public static byte[] imageToPdf(MultipartFile[] files, String fitOption, boolean autoRotate, String colorType) throws IOException {
try (PDDocument doc = new PDDocument()) {
for (MultipartFile file : files) {
String contentType = file.getContentType();
@@ -261,7 +261,7 @@ public class PdfUtils {
BufferedImage pageImage = reader.read(i);
BufferedImage convertedImage = ImageProcessingUtils.convertColorType(pageImage, colorType);
PDImageXObject pdImage = LosslessFactory.createFromImage(doc, convertedImage);
addImageToDocument(doc, pdImage, stretchToFit, autoRotate);
addImageToDocument(doc, pdImage, fitOption, autoRotate);
}
} else {
File imageFile = Files.createTempFile("image", ".png").toFile();
@@ -279,7 +279,7 @@ public class PdfUtils {
} else {
pdImage = LosslessFactory.createFromImage(doc, convertedImage);
}
addImageToDocument(doc, pdImage, stretchToFit, autoRotate);
addImageToDocument(doc, pdImage, fitOption, autoRotate);
} catch (IOException e) {
logger.error("Error writing image to file: {}", imageFile.getAbsolutePath(), e);
throw e;
@@ -295,12 +295,20 @@ public class PdfUtils {
}
}
private static void addImageToDocument(PDDocument doc, PDImageXObject image, boolean stretchToFit, boolean autoRotate) throws IOException {
private static void addImageToDocument(PDDocument doc, PDImageXObject image, String fitOption, boolean autoRotate) throws IOException {
boolean imageIsLandscape = image.getWidth() > image.getHeight();
PDRectangle pageSize = PDRectangle.A4;
System.out.println(fitOption);
if (autoRotate && imageIsLandscape) {
pageSize = new PDRectangle(pageSize.getHeight(), pageSize.getWidth());
}
if ("fitDocumentToImage".equals(fitOption)) {
pageSize = new PDRectangle(image.getWidth(), image.getHeight());
}
PDPage page = new PDPage(pageSize);
doc.addPage(page);
@@ -308,9 +316,9 @@ public class PdfUtils {
float pageHeight = page.getMediaBox().getHeight();
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
if (stretchToFit) {
if ("fillPage".equals(fitOption) || "fitDocumentToImage".equals(fitOption)) {
contentStream.drawImage(image, 0, 0, pageWidth, pageHeight);
} else {
} else if ("maintainAspectRatio".equals(fitOption)) {
float imageAspectRatio = (float) image.getWidth() / (float) image.getHeight();
float pageAspectRatio = pageWidth / pageHeight;
@@ -331,6 +339,7 @@ public class PdfUtils {
}
}
public static byte[] overlayImage(byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage) throws IOException {
PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes));

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=Split
imageToPDF.title=صورة إلى PDF
imageToPDF.header=صورة إلى PDF
imageToPDF.submit=تحول
imageToPDF.selectText.1=\u062A\u0645\u062F\u062F \u0644\u0644\u0645\u0644\u0627\u0621\u0645\u0629
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=\u062F\u0648\u0631\u0627\u0646 PDF \u062A\u0644\u0642\u0627\u0626\u064A\u064B\u0627
imageToPDF.selectText.3=\u0627\u0644\u0645\u0646\u0637\u0642 \u0627\u0644\u0645\u062A\u0639\u062F\u062F \u0644\u0644\u0645\u0644\u0641\u0627\u062A (\u0645\u0641\u0639\u0651\u0644 \u0641\u0642\u0637 \u0625\u0630\u0627 \u0643\u0646\u062A \u062A\u0639\u0645\u0644 \u0645\u0639 \u0635\u0648\u0631 \u0645\u062A\u0639\u062F\u062F\u0629)
imageToPDF.selectText.4=\u062F\u0645\u062C \u0641\u064A \u0645\u0644\u0641 PDF \u0648\u0627\u062D\u062F

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=Divideix
imageToPDF.title=Imatge a PDF
imageToPDF.header=Imatge a PDF
imageToPDF.submit=Converteix
imageToPDF.selectText.1=Estirar per adaptar
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Auto rota PDF
imageToPDF.selectText.3=Lògica de diversos fitxers (només està activada si es treballa amb diverses imatges)
imageToPDF.selectText.4=Combina en un únic PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Mehrseitiges Layout
pageLayout.header=Mehrseitiges Layout
pageLayout.pagesPerSheet=Seiten pro Blatt:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Abschicken
@@ -665,7 +669,10 @@ split.submit=Aufteilen
imageToPDF.title=Bild zu PDF
imageToPDF.header=Bild zu PDF
imageToPDF.submit=Umwandeln
imageToPDF.selectText.1=Auf Seite strecken
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=PDF automatisch drehen
imageToPDF.selectText.3=Mehrere Dateien verarbeiten (nur aktiv, wenn Sie mit mehreren Bildern arbeiten)
imageToPDF.selectText.4=In ein einziges PDF zusammenführen

View File

@@ -478,6 +478,7 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +666,10 @@ split.submit=Split
imageToPDF.title=Image to PDF
imageToPDF.header=Image to PDF
imageToPDF.submit=Convert
imageToPDF.selectText.1=Stretch to fit
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
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

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=Split
imageToPDF.title=Image to PDF
imageToPDF.header=Image to PDF
imageToPDF.submit=Convert
imageToPDF.selectText.1=Stretch to fit
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
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

View File

@@ -31,23 +31,23 @@ sizes.medium=Mediano
sizes.large=Grande
sizes.x-large=Extra grande
error.pdfPassword=El documento PDF está protegido con contraseña y no se ha proporcionado o es incorrecta
delete=Delete
username=Username
password=Password
welcome=Welcome
property=Property
black=Black
white=White
red=Red
green=Green
blue=Blue
custom=Custom...
delete=Borrar
username=Nombre de usuario
password=Contraseña
welcome=Bienvenido
property=Propietario
black=Negro
white=Blanco
red=Rojo
green=Verde
blue=Azul
custom=Personalizado...
changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists.
changedCredsMessage=Se cambiaron las credenciales!
notAuthenticatedMessage=Usuario njo autentificado.
userNotFoundMessage=Usuario no encontrado.
incorrectPasswordMessage=La contraseña actual no es correcta.
usernameExistsMessage=El nuevo nombre de usuario está en uso.
@@ -59,12 +59,12 @@ navbar.security=Seguridad
navbar.other=Otro
navbar.darkmode=Modo oscuro
navbar.pageOps=Operaciones de página
navbar.settings=Ajustes
navbar.settings=Configuración
#############
# SETTINGS #
#############
settings.title=Ajustes
settings.title=Configuración
settings.update=Actualización disponible
settings.appVersion=Versión de la aplicación:
settings.downloadOption.title=Elegir la opción de descarga (para descargas de un solo archivo sin ZIP):
@@ -72,55 +72,55 @@ settings.downloadOption.1=Abrir en la misma ventana
settings.downloadOption.2=Abrir en una nueva ventana
settings.downloadOption.3=Descargar el fichero
settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descargados
settings.signOut=Sign Out
settings.accountSettings=Account Settings
settings.signOut=Desconectar
settings.accountSettings=Configuración de la cuenta
changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted)
changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password
changeCreds.confirmNewPassword=Confirm New Password
changeCreds.submit=Submit Changes
changeCreds.title=Cambiar Credenciales
changeCreds.header=Actualice los detalles de su cuenta
changeCreds.changeUserAndPassword=Está usando las credenciales por defecto. Por favor, introduzca una nueva contraseña (y usuario si lo desea)
changeCreds.newUsername=Nuevo usuario
changeCreds.oldPassword=Contraseña actual
changeCreds.newPassword=Nueva contraseña
changeCreds.confirmNewPassword=Confirme la nueva contraseña
changeCreds.submit=Enviar cambios
account.title=Account Settings
account.accountSettings=Account Settings
account.adminSettings=Admin Settings - View and Add Users
account.userControlSettings=User Control Settings
account.changeUsername=Change Username
account.changeUsername=Change Username
account.password=Confirmation Password
account.oldPassword=Old password
account.newPassword=New Password
account.changePassword=Change Password
account.confirmNewPassword=Confirm New Password
account.signOut=Sign Out
account.yourApiKey=Your API Key
account.syncTitle=Sync browser settings with Account
account.settingsCompare=Settings Comparison:
account.property=Property
account.webBrowserSettings=Web Browser Setting
account.syncToBrowser=Sync Account -> Browser
account.syncToAccount=Sync Account <- Browser
account.title=Configuración de la cuenta
account.accountSettings=Configuración de la cuenta
account.adminSettings=Configuración de Administrador - Ver y Añadir Usuarios
account.userControlSettings=Configuración de control de usuario
account.changeUsername=Cambiar nombre de usuario
account.changeUsername=Cambiar nombre de usuario
account.password=Confirmar contraseña
account.oldPassword=Contraseña anterior
account.newPassword=Nueva Contraseña
account.changePassword=Cambiar Contraseña
account.confirmNewPassword=Confirmar Nueva Contraseña
account.signOut=Cerrar sesión
account.yourApiKey=Su clave API
account.syncTitle=Sincronizar la configuración del navegador con la cuenta
account.settingsCompare=Comparación de configuraciones:
account.property=Propiedad
account.webBrowserSettings=Configuración del navegador
account.syncToBrowser=Sincronizar cuenta -> Navegador
account.syncToAccount=Sincronizar cuenta <- Navegador
adminUserSettings.title=User Control Settings
adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin
adminUserSettings.user=User
adminUserSettings.addUser=Add New User
adminUserSettings.title=Configuración de control de usuario
adminUserSettings.header=Configuración de control de usuario administrador
adminUserSettings.admin=Administrador
adminUserSettings.user=Usuario
adminUserSettings.addUser=Añadir Nuevo Usuario
adminUserSettings.roles=Roles
adminUserSettings.role=Role
adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User
adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.forceChange=Force user to change username/password on login
adminUserSettings.submit=Save User
adminUserSettings.role=Rol
adminUserSettings.actions=Acciones
adminUserSettings.apiUser=Usuario limitado de API
adminUserSettings.webOnlyUser=Usuario solo web
adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso
adminUserSettings.submit=Guardar Usuario
#############
# HOME-PAGE #
@@ -130,7 +130,7 @@ home.desc=Su ventanilla única autohospedada para todas tus necesidades PDF
home.multiTool.title=Multi-herramienta PDF
home.multiTool.desc=Combinar, rotar, reorganizar y eliminar páginas
multiTool.tags=Multi-herramienta,Multi-operación,Interfaz de usuario,Arrastrar con un click,front end,lado del client
multiTool.tags=Multi-herramienta,Multi-operación,Interfaz de usuario,Arrastrar con un click,front end,lado del cliente
home.merge.title=Unir
home.merge.desc=Unir fácilmente múltiples PDFs en uno
@@ -270,12 +270,12 @@ home.pipeline.title=Secuencia (Avanzado)
home.pipeline.desc=Ejecutar varias tareas a PDFs definiendo una secuencia de comandos
pipeline.tags=automatizar,secuencia,con script,proceso por lotes
home.add-page-numbers.title=Aádir números de página
home.add-page-numbers.desc=Aádir números de página en un documento en una ubicación concreta
home.add-page-numbers.title=Añadir números de página
home.add-page-numbers.desc=Añadir números de página en un documento en una ubicación concreta
add-page-numbers.tags=paginar,etiquetar,organizar,indexar
home.auto-rename.title=Auto renombrar archivo PDF
home.auto-rename.desc=Auto renormbrar un archivo PDF según su encabezamiento detecetado
home.auto-rename.desc=Auto renombrar un archivo PDF según el encabezamiento detectado
auto-rename.tags=auto-detectar,basado en el encabezamiento,organizar,re-etiquetar
home.adjust-contrast.title=Ajustar Color/Contraste
@@ -303,32 +303,32 @@ home.HTMLToPDF.desc=Convierte cualquier archivo HTML o ZIP a PDF
HTMLToPDF.tags=margen,contenido web,transformación,convertir
home.MarkdownToPDF.title=Markdown to PDF
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
MarkdownToPDF.tags=markup,web-content,transformation,convert
home.MarkdownToPDF.title=Markdown a PDF
home.MarkdownToPDF.desc=Convierte cualquier archivo Markdown a PDF
MarkdownToPDF.tags=margen,contenido web,transformación,convertir
home.getPdfInfo.title=Get ALL Info on PDF
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
getPdfInfo.tags=infomation,data,stats,statistics
home.getPdfInfo.title=Obtener toda la información en PDF
home.getPdfInfo.desc=Obtiene toda la información posible de archivos PDF
getPdfInfo.tags=información,datos,stats,estasticas
home.extractPage.title=Extract page(s)
home.extractPage.desc=Extracts select pages from PDF
extractPage.tags=extract
home.extractPage.title=Extraer página(s)
home.extractPage.desc=Extraer las páginas seleccionadas del PDF
extractPage.tags=extraer
home.PdfToSinglePage.title=PDF to Single Large Page
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
PdfToSinglePage.tags=single page
home.PdfToSinglePage.title=PDF a una sola página
home.PdfToSinglePage.desc=Unir todas las páginas del PDF en una sola página
PdfToSinglePage.tags=página única
home.showJS.title=Show Javascript
home.showJS.desc=Searches and displays any JS injected into a PDF
home.showJS.title=Mostrar Javascript
home.showJS.desc=Busca y muestra cualquier JS contenido en un PDF
showJS.tags=JS
home.autoRedact.title=Auto Redact
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
home.autoRedact.title=Auto Redactar
home.autoRedact.desc=Redactar automáticamente (ocultar) texto en un PDF según el texto introducido
showJS.tags=JS
###########################
@@ -337,59 +337,59 @@ showJS.tags=JS
# #
###########################
#login
login.title=Sign in
login.signin=Sign in
login.rememberme=Remember me
login.invalid=Invalid username or password.
login.locked=Your account has been locked.
login.signinTitle=Please sign in
login.title=Iniciar sesión
login.signin=Iniciar sesión
login.rememberme=Recordarme
login.invalid=Nombre de usuario o contraseña erróneos.
login.locked=Su cuenta se ha bloqueado.
login.signinTitle=Por favor, inicie sesión
#auto-redact
autoRedact.title=Auto Redact
autoRedact.header=Auto Redact
autoRedact.colorLabel=Colour
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
autoRedact.useRegexLabel=Use Regex
autoRedact.wholeWordSearchLabel=Whole Word Search
autoRedact.customPaddingLabel=Custom Extra Padding
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
autoRedact.submitButton=Submit
autoRedact.title=Auto Redactar
autoRedact.header=Auto Redactar
autoRedact.colorLabel=Color
autoRedact.textsToRedactLabel=Texto para Redactar (separado por líneas)
autoRedact.textsToRedactPlaceholder=por ej. \nConfidencial \nAlto-Secreto
autoRedact.useRegexLabel=Usar Regex
autoRedact.wholeWordSearchLabel=Búsqueda por palabra completa
autoRedact.customPaddingLabel=Extra Padding personalizado
autoRedact.convertPDFToImageLabel=Convertir PDF a imagen-PDF (Utilizado para quitar el texto detrás del cajetín)
autoRedact.submitButton=Enviar
#showJS
showJS.title=Show Javascript
showJS.header=Show Javascript
showJS.downloadJS=Download Javascript
showJS.submit=Show
showJS.title=Mostrar Javascript
showJS.header=Mostrar Javascript
showJS.downloadJS=Descargar Javascript
showJS.submit=Mostrar
#pdfToSinglePage
pdfToSinglePage.title=PDF To Single Page
pdfToSinglePage.header=PDF To Single Page
pdfToSinglePage.submit=Convert To Single Page
pdfToSinglePage.title=PDF a página única
pdfToSinglePage.header=PDF a página única
pdfToSinglePage.submit=Convertir a página única
#pageExtracter
pageExtracter.title=Extract Pages
pageExtracter.header=Extract Pages
pageExtracter.submit=Extract
pageExtracter.title=Extraer Páginas
pageExtracter.header=Extraer Páginas
pageExtracter.submit=Extraer
#getPdfInfo
getPdfInfo.title=Get Info on PDF
getPdfInfo.header=Get Info on PDF
getPdfInfo.submit=Get Info
getPdfInfo.downloadJson=Download JSON
getPdfInfo.title=Obtener Información del PDF
getPdfInfo.header=Obtener Información del PDF
getPdfInfo.submit=Obtener Información
getPdfInfo.downloadJson=Descargar JSON
#markdown-to-pdf
MarkdownToPDF.title=Markdown To PDF
MarkdownToPDF.header=Markdown To PDF
MarkdownToPDF.submit=Convert
MarkdownToPDF.help=Work in progress
MarkdownToPDF.credit=Uses WeasyPrint
MarkdownToPDF.title=Markdown a PDF
MarkdownToPDF.header=Markdown a PDF
MarkdownToPDF.submit=Convertir
MarkdownToPDF.help=Tarea en proceso
MarkdownToPDF.credit=Usa WeasyPrint
@@ -428,9 +428,9 @@ addPageNumbers.selectText.3=Posición
addPageNumbers.selectText.4=Número de inicio
addPageNumbers.selectText.5=Páginas a numerar
addPageNumbers.selectText.6=Texto personalizado
addPageNumbers.customTextDesc=Custom Text
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
addPageNumbers.customTextDesc=Texto personalizado
addPageNumbers.numberPagesDesc=Qué páginas numerar, por defecto 'todas', también acepta 1-5 o 2,5,9 etc
addPageNumbers.customNumberDesc=Por defecto a {n}, también acepta 'Página {n} de {total}', 'Texto-{n}', '{nombre de archivo}-{n}
addPageNumbers.submit=Añadir Números de Página
@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Diseño de varias páginas
pageLayout.header=Diseño de varias páginas
pageLayout.pagesPerSheet=Páginas por hoja:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Entregar
@@ -616,8 +620,8 @@ addImage.submit=Añadir imagen
#merge
merge.title=Unir
merge.header=Unir múltiples PDFs (2+)
merge.sortByName=Sort by name
merge.sortByDate=Sort by date
merge.sortByName=Ordenar por nombre
merge.sortByDate=Ordenar por fecha
merge.submit=Unir
@@ -642,7 +646,7 @@ pageRemover.submit=Eliminar Páginas
#rotate
rotate.title=Rotar PDF
rotate.header=Rotar PDF
rotate.selectAngle=Select rotation angle (in multiples of 90 degrees):
rotate.selectAngle=Seleccionar ángulo de rotación (en múltiplos de 90 grados):
rotate.submit=Rotar
@@ -665,7 +669,10 @@ split.submit=Dividir
imageToPDF.title=Imagen a PDF
imageToPDF.header=Imagen a PDF
imageToPDF.submit=Convertir
imageToPDF.selectText.1=Estirar para ajustar
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Rotación automática del PDF
imageToPDF.selectText.3=Lógica de archivos múltiples (únicamente activado si funciona con multiples imágenes)
imageToPDF.selectText.4=Unir en un único archivo PDF
@@ -718,8 +725,8 @@ watermark.selectText.4=Rotación (0-360):
watermark.selectText.5=Ancho (Espacio entre cada marca de agua horizontalmente):
watermark.selectText.6=Alto (Espacio entre cada marca de agua verticalmente):
watermark.selectText.7=Opacidad (0% - 100%):
watermark.selectText.8=Watermark Type:
watermark.selectText.9=Watermark Image:
watermark.selectText.8=Tipo de marca de agua:
watermark.selectText.9=Imagen de marca de agua:
watermark.submit=Añadir marca de agua
@@ -762,7 +769,7 @@ changeMetadata.modDate=Fecha de modificación (aaaa/MM/dd HH:mm:ss):
changeMetadata.producer=Productor:
changeMetadata.subject=Asunto:
changeMetadata.title=Título:
changeMetadata.trapped=Trapped:
changeMetadata.trapped=Capturado:
changeMetadata.selectText.4=Otros Metadatos:
changeMetadata.selectText.5=Agregar entrada de metadatos personalizados
changeMetadata.submit=Cambiar

View File

@@ -478,6 +478,10 @@ pipeline.title=Hodia
pageLayout.title=Hainbat orrialderen diseinua
pageLayout.header=Hainbat orrialderen diseinua
pageLayout.pagesPerSheet=Orrialdeak orriko:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Entregatu
@@ -665,7 +669,10 @@ split.submit=Zatitu
imageToPDF.title=Irudia PDF bihurtu
imageToPDF.header=Irudia PDF bihurtu
imageToPDF.submit=Bihurtu
imageToPDF.selectText.1=Zabaldu doitzeko
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=PDFaren errotazio automatikoa
imageToPDF.selectText.3=Fitxategi askoren logika (gaituta bakarrik zenbait irudirekin ari denean)
imageToPDF.selectText.4=Elkartu PDF bakar batean

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Fusionner des pages
pageLayout.header=Fusionner des pages
pageLayout.pagesPerSheet=Pages par feuille
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Fusionner
@@ -665,7 +669,10 @@ split.submit=Diviser
imageToPDF.title=Image en PDF
imageToPDF.header=Image en PDF
imageToPDF.submit=Convertir
imageToPDF.selectText.1=Étirer pour adapter
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Rotation automatique du PDF
imageToPDF.selectText.3=Logique multi-fichiers (uniquement activée si vous travaillez avec plusieurs images)
imageToPDF.selectText.4=Fusionner en un seul PDF
@@ -749,7 +756,7 @@ removePassword.submit=Supprimer
#changeMetadata
changeMetadata.title=Modifier les métadonnées
changeMetadata.title=Titre
changeMetadata.header=Modifier les métadonnées
changeMetadata.selectText.1=Veuillez modifier les variables que vous souhaitez modifier.
changeMetadata.selectText.2=Supprimer toutes les métadonnées

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Layout multipagina
pageLayout.header=Layout multipagina
pageLayout.pagesPerSheet=Pagine per foglio:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Invia
@@ -665,7 +669,10 @@ split.submit=Dividi
imageToPDF.title=Immagine a PDF
imageToPDF.header=Immagine a PDF
imageToPDF.submit=Converti
imageToPDF.selectText.1=Allarga per riempire
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Ruota automaticamente PDF
imageToPDF.selectText.3=Logica multi-file (funziona solo se ci sono più immagini)
imageToPDF.selectText.4=Unisci in un unico PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=パイプライン
pageLayout.title=マルチページレイアウト
pageLayout.header=マルチページレイアウト
pageLayout.pagesPerSheet=1枚あたりのページ数:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=送信
@@ -665,7 +669,10 @@ split.submit=分割
imageToPDF.title=画像をPDFに変換
imageToPDF.header=画像をPDFに変換
imageToPDF.submit=変換
imageToPDF.selectText.1=フィットするように引き伸ばす
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=PDFの自動回転
imageToPDF.selectText.3=マルチファイルの処理 (複数の画像を操作する場合に有効になります)
imageToPDF.selectText.4=1つのPDFに結合

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=분할
imageToPDF.title=이미지를 PDF로 변환
imageToPDF.header=이미지를 PDF로 변환
imageToPDF.submit=변환하기
imageToPDF.selectText.1=맞춤 크기로 늘리기
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=PDF 자동 회전
imageToPDF.selectText.3=다중 파일 로직 (여러 이미지로 작업하는 경우에만 활성화됨)
imageToPDF.selectText.4=단일 PDF로 병합

View File

@@ -478,6 +478,10 @@ pipeline.title=Pijplijn
pageLayout.title=Meerdere pagina indeling
pageLayout.header=Meerdere pagina indeling
pageLayout.pagesPerSheet=Pagina''s per vel:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Indienen
@@ -665,7 +669,10 @@ split.submit=Splitsen
imageToPDF.title=Afbeelding naar PDF
imageToPDF.header=Afbeelding naar PDF
imageToPDF.submit=Omzetten
imageToPDF.selectText.1=Uitrekken om te passen
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=PDF automatisch draaien
imageToPDF.selectText.3=Meervoudige bestandslogica (Alleen ingeschakeld bij werken met meerdere afbeeldingen)
imageToPDF.selectText.4=Voeg samen in één PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Układ wielu stron
pageLayout.header=Układ wielu stron
pageLayout.pagesPerSheet=Stron na jednym arkuszu:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Wykonaj
@@ -665,7 +669,10 @@ split.submit=Podziel
imageToPDF.title=Obraz na PDF
imageToPDF.header=Obraz na PDF
imageToPDF.submit=Konwertuj
imageToPDF.selectText.1=Rozciągnij, aby dopasować
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Automatyczne obracanie PDF
imageToPDF.selectText.3=Logika wielu plików (dostępna tylko w przypadku pracy z wieloma obrazami)
imageToPDF.selectText.4=Połącz w jeden dokument PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Layout de Múltiplas Páginas
pageLayout.header=Layout de Múltiplas Páginas
pageLayout.pagesPerSheet=Páginas por folha:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Enviar
@@ -665,7 +669,10 @@ split.submit=Dividir
imageToPDF.title=Imagem para PDF
imageToPDF.header=Converter Imagem para PDF
imageToPDF.submit=Converter
imageToPDF.selectText.1=Esticar para Ajustar
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Girar Automaticamente
imageToPDF.selectText.3=Lógica de Vários Arquivos (Ativada apenas ao trabalhar com várias imagens)
imageToPDF.selectText.4=Mesclar em um Único PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=Împarte
imageToPDF.title=Imagine în PDF
imageToPDF.header=Imagine în PDF
imageToPDF.submit=Convertă
imageToPDF.selectText.1=Redimensionare pentru a se potrivi
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Rotire automată a PDF-ului
imageToPDF.selectText.3=Logica pentru mai multe fișiere (activată numai dacă se lucrează cu mai multe imagini)
imageToPDF.selectText.4=Unifică într-un singur PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=Разделить
imageToPDF.title=Изображение в PDF
imageToPDF.header=Изображение в PDF
imageToPDF.submit=Конвертировать
imageToPDF.selectText.1=Растянуть, чтобы соответствовать
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Автоматический поворот PDF
imageToPDF.selectText.3=Многофайловая логика (включена только при работе с несколькими изображениями)
imageToPDF.selectText.4=Объединить в один PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=Dela
imageToPDF.title=Bild till PDF
imageToPDF.header=Bild till PDF
imageToPDF.submit=Konvertera
imageToPDF.selectText.1=Sträck för att passa
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=Rotera PDF automatiskt
imageToPDF.selectText.3=Multifillogik (Endast aktiverad om man arbetar med flera bilder)
imageToPDF.selectText.4=Slå samman till en enda PDF

View File

@@ -478,6 +478,10 @@ pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
##########################
### TODO: Translate ###
##########################
pageLayout.addBorder=Add Borders
pageLayout.submit=Submit
@@ -665,7 +669,10 @@ split.submit=拆分
imageToPDF.title=图片转PDF
imageToPDF.header=图像转为PDF
imageToPDF.submit=转换
imageToPDF.selectText.1=拉伸至适合的尺寸
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=自动旋转PDF
imageToPDF.selectText.3=多文件逻辑(仅在处理多个图像时启用)
imageToPDF.selectText.4=合并成一个PDF文件

View File

@@ -21,10 +21,16 @@
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="stretchToFit" id="stretchToFit">
<label class="ms-3" for="stretchToFit" th:text=#{imageToPDF.selectText.1}></label>
</div>
<div class="mb-3">
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label>
<select class="form-control" id="fitOption" name="fitOption">
<option value="fillPage" th:text="#{imageToPDF.fillPage}">Fill Page</option>
<option value="fitDocumentToImage" th:text="#{imageToPDF.fitDocumentToImage}">Fit Document to Image</option>
<option value="maintainAspectRatio" th:text="#{imageToPDF.maintainAspectRatio}">Maintain Aspect Ratio</option>
</select>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="autoRotate" id="autoRotate">
<label class="ms-3" for="autoRotate" th:text=#{imageToPDF.selectText.2}></label>

View File

@@ -26,6 +26,10 @@
<option value="16">16</option>
</select>
</div>
<div class="mb-3">
<input type="checkbox" class="form-check-input" id="addBorder" name="addBorder">
<label class="form-check-label" for="addBorder" th:text="#{pageLayout.addBorder}"></label>
</div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageLayout.submit}"></button>
</form>
</div>

View File

@@ -35,19 +35,19 @@
<div class="mb-3" id="p12Group" style="display: none;">
<label th:text="#{certSign.selectP12}"></label>
<div
th:replace="~{fragments/common :: fileSelector(name='p12', notRequired=true, multiple=false, accept='.p12,.pfx')}"></div>
th:replace="~{fragments/common :: fileSelector(name='p12File', notRequired=true, multiple=false, accept='.p12,.pfx')}"></div>
</div>
<div id="pemGroup" style="display: none;">
<div class="mb-3">
<label th:text="#{certSign.selectKey}"></label>
<div
th:replace="~{fragments/common :: fileSelector(name='key', multiple=false, notRequired=true, accept='.pem,.der')}"></div>
th:replace="~{fragments/common :: fileSelector(name='privateKeyFile', multiple=false, notRequired=true, accept='.pem,.der')}"></div>
</div>
<div class="mb-3">
<label th:text="#{certSign.selectCert}"></label>
<div
th:replace="~{fragments/common :: fileSelector(name='cert', multiple=false, notRequired=true, accept='.pem,.der')}"></div>
th:replace="~{fragments/common :: fileSelector(name='certFile', multiple=false, notRequired=true, accept='.pem,.der')}"></div>
</div>
</div>

View File

@@ -20,7 +20,7 @@
</div>
<div class="mb-3">
<label th:text="#{removePassword.selectText.2}"></label>
<input type="password" class="form-control" id="password" name="password" required>
<input type="password" class="form-control" id="password" name="password">
</div>
<br />
<div class="mb-3 text-center">