From 1fc1ecbaa6d13edae02af45cc412cbb753377522 Mon Sep 17 00:00:00 2001
From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
Date: Thu, 28 Sep 2023 12:35:44 -0500
Subject: [PATCH 1/3] Update remove-password.html
allow removal of encryption without password #383
---
src/main/resources/templates/security/remove-password.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/resources/templates/security/remove-password.html b/src/main/resources/templates/security/remove-password.html
index cec61959..af8675d1 100644
--- a/src/main/resources/templates/security/remove-password.html
+++ b/src/main/resources/templates/security/remove-password.html
@@ -20,7 +20,7 @@
-
+
From c5ea2549450e708943e368cae1c1a8f33aec1590 Mon Sep 17 00:00:00 2001
From: JerronAB <92005206+JerronAB@users.noreply.github.com>
Date: Fri, 29 Sep 2023 16:00:22 -0400
Subject: [PATCH 2/3] Removed numpy library from blank page py script
---
scripts/detect-blank-pages.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/scripts/detect-blank-pages.py b/scripts/detect-blank-pages.py
index 6712dc12..474c2735 100644
--- a/scripts/detect-blank-pages.py
+++ b/scripts/detect-blank-pages.py
@@ -1,5 +1,4 @@
import cv2
-import numpy as np
import sys
import argparse
From e0f306d3f78f6fdb4c50111b16b4d3b48b48989c Mon Sep 17 00:00:00 2001
From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
Date: Fri, 29 Sep 2023 23:58:37 +0100
Subject: [PATCH 3/3] updates
---
Dockerfile-lite | 28 ++++----
README.md | 8 ++-
build.gradle | 2 +-
.../config/security/InitialSecuritySetup.java | 13 +++-
.../api/MultiPageLayoutController.java | 16 ++++-
.../api/misc/ExtractImagesController.java | 15 +++-
.../controller/api/security/GetInfoOnPDF.java | 68 +++++++++++++------
.../SPDF/model/ApplicationProperties.java | 41 ++++++++++-
.../general/MergeMultiplePagesRequest.java | 3 +
src/main/resources/messages_ar_AR.properties | 7 +-
src/main/resources/messages_ca_CA.properties | 7 +-
src/main/resources/messages_de_DE.properties | 7 +-
src/main/resources/messages_en_GB.properties | 1 +
src/main/resources/messages_en_US.properties | 7 +-
src/main/resources/messages_es_ES.properties | 7 +-
src/main/resources/messages_eu_ES.properties | 7 +-
src/main/resources/messages_fr_FR.properties | 7 +-
src/main/resources/messages_it_IT.properties | 7 +-
src/main/resources/messages_ja_JP.properties | 7 +-
src/main/resources/messages_ko_KR.properties | 7 +-
src/main/resources/messages_nl_NL.properties | 7 +-
src/main/resources/messages_pl_PL.properties | 7 +-
src/main/resources/messages_pt_BR.properties | 7 +-
src/main/resources/messages_ro_RO.properties | 7 +-
src/main/resources/messages_ru_RU.properties | 7 +-
src/main/resources/messages_sv_SE.properties | 7 +-
src/main/resources/messages_zh_CN.properties | 7 +-
.../templates/multi-page-layout.html | 4 ++
28 files changed, 223 insertions(+), 95 deletions(-)
diff --git a/Dockerfile-lite b/Dockerfile-lite
index 8144fff9..f41a8a8f 100644
--- a/Dockerfile-lite
+++ b/Dockerfile-lite
@@ -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"]
diff --git a/README.md b/README.md
index fda5d296..e5dcc5d8 100644
--- a/README.md
+++ b/README.md
@@ -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;``
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 06db8ab3..1840c3a4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,7 +8,7 @@ plugins {
}
group = 'stirling.software'
-version = '0.14.3'
+version = '0.14.4'
sourceCompatibility = '17'
repositories {
diff --git a/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java b/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java
index 7097020b..842375d8 100644
--- a/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java
+++ b/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java
@@ -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);
+ }
+
}
}
diff --git a/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java b/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java
index f899736f..ebe81ffd 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java
@@ -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();
+ }
}
diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java
index 03d21e64..b24ac892 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java
@@ -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 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;
diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java b/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java
index 7b4aed65..791dc736 100644
--- a/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java
+++ b/src/main/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDF.java
@@ -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 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 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) {
diff --git a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java
index 45c37efe..a72479ad 100644
--- a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java
+++ b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java
@@ -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 {
diff --git a/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java b/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java
index ab6e3510..4642cb75 100644
--- a/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java
+++ b/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java
@@ -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;
}
diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties
index 87190f5f..d8722e95 100644
--- a/src/main/resources/messages_ar_AR.properties
+++ b/src/main/resources/messages_ar_AR.properties
@@ -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,9 +669,6 @@ split.submit=Split
imageToPDF.title=صورة إلى PDF
imageToPDF.header=صورة إلى PDF
imageToPDF.submit=تحول
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties
index 51f0e33f..b6341fa0 100644
--- a/src/main/resources/messages_ca_CA.properties
+++ b/src/main/resources/messages_ca_CA.properties
@@ -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,9 +669,6 @@ split.submit=Divideix
imageToPDF.title=Imatge a PDF
imageToPDF.header=Imatge a PDF
imageToPDF.submit=Converteix
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties
index 26e61b54..34b71c66 100644
--- a/src/main/resources/messages_de_DE.properties
+++ b/src/main/resources/messages_de_DE.properties
@@ -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,9 +669,6 @@ split.submit=Aufteilen
imageToPDF.title=Bild zu PDF
imageToPDF.header=Bild zu PDF
imageToPDF.submit=Umwandeln
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties
index 6d6a7aad..cc7978c4 100644
--- a/src/main/resources/messages_en_GB.properties
+++ b/src/main/resources/messages_en_GB.properties
@@ -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
diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties
index 9ee15dbf..bc712951 100644
--- a/src/main/resources/messages_en_US.properties
+++ b/src/main/resources/messages_en_US.properties
@@ -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,9 +669,6 @@ split.submit=Split
imageToPDF.title=Image to PDF
imageToPDF.header=Image to PDF
imageToPDF.submit=Convert
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties
index 9aef8747..26e993c8 100644
--- a/src/main/resources/messages_es_ES.properties
+++ b/src/main/resources/messages_es_ES.properties
@@ -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
@@ -665,9 +669,6 @@ split.submit=Dividir
imageToPDF.title=Imagen a PDF
imageToPDF.header=Imagen a PDF
imageToPDF.submit=Convertir
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties
index a7e88caa..e0dc8e5a 100644
--- a/src/main/resources/messages_eu_ES.properties
+++ b/src/main/resources/messages_eu_ES.properties
@@ -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,9 +669,6 @@ split.submit=Zatitu
imageToPDF.title=Irudia PDF bihurtu
imageToPDF.header=Irudia PDF bihurtu
imageToPDF.submit=Bihurtu
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties
index 2936a706..d8f0e178 100644
--- a/src/main/resources/messages_fr_FR.properties
+++ b/src/main/resources/messages_fr_FR.properties
@@ -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,9 +669,6 @@ split.submit=Diviser
imageToPDF.title=Image en PDF
imageToPDF.header=Image en PDF
imageToPDF.submit=Convertir
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties
index 8f4c7afc..08a34c63 100644
--- a/src/main/resources/messages_it_IT.properties
+++ b/src/main/resources/messages_it_IT.properties
@@ -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,9 +669,6 @@ split.submit=Dividi
imageToPDF.title=Immagine a PDF
imageToPDF.header=Immagine a PDF
imageToPDF.submit=Converti
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties
index d0a01cc0..2251484f 100644
--- a/src/main/resources/messages_ja_JP.properties
+++ b/src/main/resources/messages_ja_JP.properties
@@ -478,6 +478,10 @@ pipeline.title=パイプライン
pageLayout.title=マルチページレイアウト
pageLayout.header=マルチページレイアウト
pageLayout.pagesPerSheet=1枚あたりのページ数:
+##########################
+### TODO: Translate ###
+##########################
+pageLayout.addBorder=Add Borders
pageLayout.submit=送信
@@ -665,9 +669,6 @@ split.submit=分割
imageToPDF.title=画像をPDFに変換
imageToPDF.header=画像をPDFに変換
imageToPDF.submit=変換
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties
index 5929d971..b4c2fa36 100644
--- a/src/main/resources/messages_ko_KR.properties
+++ b/src/main/resources/messages_ko_KR.properties
@@ -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,9 +669,6 @@ split.submit=분할
imageToPDF.title=이미지를 PDF로 변환
imageToPDF.header=이미지를 PDF로 변환
imageToPDF.submit=변환하기
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_nl_NL.properties b/src/main/resources/messages_nl_NL.properties
index 8d7340c8..a13c9071 100644
--- a/src/main/resources/messages_nl_NL.properties
+++ b/src/main/resources/messages_nl_NL.properties
@@ -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,9 +669,6 @@ split.submit=Splitsen
imageToPDF.title=Afbeelding naar PDF
imageToPDF.header=Afbeelding naar PDF
imageToPDF.submit=Omzetten
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties
index d3bf7d7c..a2c06fc1 100644
--- a/src/main/resources/messages_pl_PL.properties
+++ b/src/main/resources/messages_pl_PL.properties
@@ -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,9 +669,6 @@ split.submit=Podziel
imageToPDF.title=Obraz na PDF
imageToPDF.header=Obraz na PDF
imageToPDF.submit=Konwertuj
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties
index 2c2f0217..879f3715 100644
--- a/src/main/resources/messages_pt_BR.properties
+++ b/src/main/resources/messages_pt_BR.properties
@@ -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,9 +669,6 @@ split.submit=Dividir
imageToPDF.title=Imagem para PDF
imageToPDF.header=Converter Imagem para PDF
imageToPDF.submit=Converter
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties
index f331519a..46dad1ba 100644
--- a/src/main/resources/messages_ro_RO.properties
+++ b/src/main/resources/messages_ro_RO.properties
@@ -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,9 +669,6 @@ split.submit=Împarte
imageToPDF.title=Imagine în PDF
imageToPDF.header=Imagine în PDF
imageToPDF.submit=Convertă
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties
index 74bb5a68..065106df 100644
--- a/src/main/resources/messages_ru_RU.properties
+++ b/src/main/resources/messages_ru_RU.properties
@@ -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,9 +669,6 @@ split.submit=Разделить
imageToPDF.title=Изображение в PDF
imageToPDF.header=Изображение в PDF
imageToPDF.submit=Конвертировать
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties
index b1b63ded..e2fc2eb8 100644
--- a/src/main/resources/messages_sv_SE.properties
+++ b/src/main/resources/messages_sv_SE.properties
@@ -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,9 +669,6 @@ split.submit=Dela
imageToPDF.title=Bild till PDF
imageToPDF.header=Bild till PDF
imageToPDF.submit=Konvertera
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties
index ddf8639a..bf6aede0 100644
--- a/src/main/resources/messages_zh_CN.properties
+++ b/src/main/resources/messages_zh_CN.properties
@@ -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,9 +669,6 @@ split.submit=拆分
imageToPDF.title=图片转PDF
imageToPDF.header=图像转为PDF
imageToPDF.submit=转换
-##########################
-### TODO: Translate ###
-##########################
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Fit Page to Image
diff --git a/src/main/resources/templates/multi-page-layout.html b/src/main/resources/templates/multi-page-layout.html
index 6b1de771..35cfd50f 100644
--- a/src/main/resources/templates/multi-page-layout.html
+++ b/src/main/resources/templates/multi-page-layout.html
@@ -26,6 +26,10 @@
+
+
+
+