Compare commits

...

107 Commits

Author SHA1 Message Date
Anthony Stirling
08205ed32d Custom uid (#883)
* init

* user and pass to just pass lang update

* session management fixes and avoid demo user locking

* fix for UMASK and extract cleanups
2024-03-08 20:49:19 +00:00
Anthony Stirling
9246b42057 Login fixes (#881)
* init

* user and pass to just pass lang update

* session management fixes and avoid demo user locking

* Hardening suggestions for Stirling-PDF / loginFixes (#882)

Switch order of literals to prevent NullPointerException

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>

---------

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-03-08 18:06:40 +00:00
albanobattistella
67e4d6e3a2 Update messages_it_IT.properties (#878) 2024-03-07 21:47:21 +00:00
Anthony Stirling
cf4613d043 Password fix and others (#875)
* init

* user and pass to just pass lang update
2024-03-07 20:12:07 +00:00
Eric
2f703796e9 fix(SplitPDF): create immutable list for dynamic additions (#877) 2024-03-07 12:05:26 -05:00
albanobattistella
731dc3f3dc Update messages_it_IT.properties (#870) 2024-03-06 22:24:30 +00:00
Ludy
97472310f2 Show the user roles as real names (#867)
* Show the user roles as real names

* Add error message

* Update Role.java

* default Language without translation

* Update messages_el_GR.properties
2024-03-06 22:14:02 +00:00
Anthony Stirling
ece1d071c0 non root user and fix book/html calibre (#856)
* non root user and fix book/html calibre

* version bump

* Update docker-compose-latest.yml

* remove customApp

---------

Co-authored-by: systo <systo@host.docker.internal>
2024-03-04 20:51:49 +00:00
albanobattistella
20f532c872 Update messages_it_IT.properties (#858)
Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-03-04 20:36:18 +00:00
Ludy
bdcccfd937 🐛 Fix: index out of bounds #861 #842 (#863)
* 🐛 Fix: `index out of bounds` #861 #842

* Update RearrangePagesPDFController.java

* Update RearrangePagesPDFController.java
2024-03-04 20:14:45 +00:00
Ludy
146b8f0103 Corrected the reading of the port. See: #834 (#855)
* Corrected the reading of the port. See: #834

* Removed outdated import

---------

Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-02-25 19:15:03 -05:00
懒猫
c8a37245fa Added option to split PDF into multiple parts and merge into one PDF (#841)
* Added option to split PDF into multiple parts and merge into one PDF

* Use the mergeDocuments method in MergeController to implement merging

---------

Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-02-24 15:26:35 -05:00
Parth P Shah
af68c70239 Update SPdfApplication.java (#853)
* Update SPdfApplication.java

* Update SPdfApplication.java

* Update SPdfApplication.java

---------

Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-02-24 15:22:47 -05:00
Ludy
5bd544dcd7 Removed: Duplicate Properties Keys pt_PT (#854) 2024-02-24 19:45:07 +00:00
Anthony Stirling
642b85069d Merge pull request #852 from parth-p-shah/application-file-fixes
Application file fixes, added loggers instead of sysout
2024-02-23 19:03:04 +00:00
Parth P Shah
6fef4ea82c Update SPdfApplication.java 2024-02-24 00:01:20 +05:30
Parth P Shah
8670afb96f Revert "Update SPdfApplication.java"
This reverts commit 33f8d60900.
2024-02-23 23:46:42 +05:30
Parth P Shah
33f8d60900 Update SPdfApplication.java 2024-02-23 23:46:36 +05:30
albanobattistella
4e2156ad79 Update messages_it_IT.properties (#839) 2024-02-21 17:30:55 -05:00
Anthony Stirling
a07245224e Merge pull request #833 from seku80/main
Add messages_pt_PT.properties
2024-02-19 22:34:00 +00:00
seku80
f96a4cdb59 Update pt_PT
Fixed missing line #14 and removing duplicate entry line #870
2024-02-19 16:46:35 +00:00
seku80
efea22aa6e Update languages.html 2024-02-19 16:19:29 +00:00
seku80
ae9a7dc580 Add files via upload 2024-02-19 16:13:16 +00:00
seku80
7135ace1aa Add files via upload 2024-02-19 15:03:28 +00:00
Anthony Stirling
625275124a fix for #818 2024-02-18 15:47:19 +00:00
Anthony Stirling
c96ebccae4 Download message for game 2024-02-18 13:30:56 +00:00
Anthony Stirling
20cb460a7e controls and sizing bounds 2024-02-18 09:45:50 +00:00
Anthony Stirling
3a62d19979 game const 2024-02-18 09:21:30 +00:00
Ludy
51ad741744 Fix 746 (#825)
* Fix: #746

* formatting
2024-02-18 07:40:30 +00:00
Anthony Stirling
673f005fe6 Game fixes and ocr docs (#824) 2024-02-17 23:23:07 +00:00
Ludy
8d9f0361d0 Fix Serbia Language (#822)
* Fix Serbia Language

* Rename messages_sr_Latn_RS.properties to messages_sr_LATN_RS.properties

* Update languages.html

* Update README.md
2024-02-17 19:56:56 +00:00
Anthony Stirling
56e3ec1219 Update HowToUseOCR.md 2024-02-17 19:28:32 +00:00
dependabot[bot]
a0acafcefc Bump org.springframework:spring-webmvc from 6.1.2 to 6.1.3 (#713)
Bumps [org.springframework:spring-webmvc](https://github.com/spring-projects/spring-framework) from 6.1.2 to 6.1.3.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.2...v6.1.3)

---
updated-dependencies:
- dependency-name: org.springframework:spring-webmvc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-17 13:24:38 +00:00
dependabot[bot]
918f5954b7 Bump io.micrometer:micrometer-core from 1.12.2 to 1.12.3 (#806)
Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.2 to 1.12.3.
- [Release notes](https://github.com/micrometer-metrics/micrometer/releases)
- [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.2...v1.12.3)

---
updated-dependencies:
- dependency-name: io.micrometer:micrometer-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-17 13:23:10 +00:00
albanobattistella
148dcdaee7 Update messages_it_IT.properties (#816) 2024-02-17 13:22:15 +00:00
Anthony Stirling
a5f0777892 Update ConfigInitializer.java for auto settings removal 2024-02-17 13:10:00 +00:00
Ludy
010426d488 Document (#803)
* Update HowToAddNewLanguage.md

* Update HowToUseOCR.md

* Update LocalRunGuide.md

* Update README.md

* Update LocalRunGuide.md

* Update README.md

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-02-16 22:42:56 +00:00
Aliarev
6fc9c7be90 Update french translation (#814) 2024-02-16 22:24:26 +00:00
Sherif Metwally
094fde9801 Update-helm-chart (#815)
* upgrade app in helm chart to 0.20.2

* update and correct UI env variable names in chart values.yaml
2024-02-16 22:23:11 +00:00
Ludy
e4a76e96af HTML, CSS, JS and JAVA corrections (#810)
* CSS corrections

* HTML corrections

* JS corrections

* JAVA corrections

* remove tab

* CSS corrections 2

* JS corrections 2

* back to the roots

* max-linie 127

* add slash hr|br

* return bootstrap-icons.css

* return bootstrap-icons.min.css

* return bootstrap.min.css

* Update bootstrap-icons.css

* Update bootstrap-icons.min.css

* Update bootstrap-icons.min.css

* Update bootstrap.min.css

* CSS corrections

* HTML corrections

* JS corrections

* JAVA corrections

* remove tab

* CSS corrections 2

* JS corrections 2

* back to the roots

* max-linie 127

* add slash hr|br

* return bootstrap-icons.css

* Update bootstrap-icons.css

* Bootstrap CSS

* Update prism.css
2024-02-16 21:49:06 +00:00
Anthony Stirling
68f582bcb9 Merge pull request #811 from NeilJared/main
Update messages_es_ES.properties
2024-02-14 21:27:59 +00:00
NeilJared
639aed7120 Update messages_es_ES.properties
Updated es_ES translation
2024-02-14 12:22:47 +01:00
NeilJared
994bb4d1d2 Update messages_es_ES.properties
Minor bug fixes: es_ES translation
2024-02-14 11:57:34 +01:00
Anthony Stirling
80b11a55fa Merge pull request #804 from Ludy87/missing_pageSelectionPrompt
add missing propertie pageSelectionPrompt
2024-02-11 22:43:08 +00:00
Ludy87
3cfb554623 missing propertie pageSelectionPrompt 2024-02-11 21:10:04 +01:00
Eric
e84f9c5946 Merge pull request #796 from Ludy87/languages
Languages
2024-02-11 14:41:15 -05:00
Ludy87
17cc31d6e7 add placeholder translation 2024-02-11 14:32:34 -05:00
Ludy87
0c6e10a6dd add separator 2024-02-11 14:32:34 -05:00
Ludy87
297c57631f remove dublicate -> change showJS.tags to autoRedact.tags 2024-02-11 14:32:34 -05:00
Ludy87
bd4e252bb6 added missing strings 2024-02-11 14:32:33 -05:00
Ludy87
0ce34c70bc Update messages_de_DE.properties 2024-02-11 14:32:33 -05:00
Ludy87
4df75cfba1 Update messages_de_DE.properties 2024-02-11 14:32:33 -05:00
Ludy87
2aa435bcfb double spaces removed 2024-02-11 14:32:33 -05:00
Ludy87
0a4a9e6947 Removed unnecessary characters and added DE missing strings 2024-02-11 14:32:32 -05:00
Anthony Stirling
d5860d0b55 Update PdfToTextOrRTFRequest.java 2024-02-11 18:47:43 +00:00
Eric
6a487ce514 Merge pull request #802 from Stirling-Tools/normalize_files
refactor: normalize all files (strip trailing whitespace + convert CRLF to LF)
2024-02-11 13:11:37 -05:00
sbplat
4f3b85e66b refactor: normalize files that contained both CRLF and LF 2024-02-11 12:14:21 -05:00
sbplat
370cd97e05 misc: update .git-blame-ignore-revs to ignore normalize files commit in blame 2024-02-11 11:54:03 -05:00
sbplat
55d4fda01b refactor: normalize files 2024-02-11 11:47:00 -05:00
Anthony Stirling
3dd0471e22 Merge pull request #799 from Stirling-Tools/icon
Icon changes!
2024-02-10 16:40:00 +00:00
Anthony Stirling
5a4efa81a7 more icon changes 2024-02-10 16:22:59 +00:00
Anthony Stirling
ea59c12b27 icon changes 2024-02-10 16:17:47 +00:00
Anthony Stirling
9600f91dda bigger icons 2024-02-10 16:11:45 +00:00
Anthony Stirling
a9f93b014a icon change 2024-02-10 15:56:41 +00:00
Anthony Stirling
bf62e389f7 Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into
main
2024-02-10 14:55:53 +00:00
Anthony Stirling
26af6b5636 cleanups formatting 2024-02-10 14:52:59 +00:00
Anthony Stirling
0fabfea56d page adjusts for stamp 2024-02-10 14:52:27 +00:00
Anthony Stirling
7a9417a62f Merge pull request #794 from mannam11/fixed-stamptool-wrong-filename-generaion-#757
fixed wrong filename generation through stamp tool #757
2024-02-10 11:21:19 +00:00
Anthony Stirling
eb45005baa Merge branch 'main' into fixed-stamptool-wrong-filename-generaion-#757 2024-02-10 11:20:21 +00:00
Anthony Stirling
a4f923eb3a Update StampController.java 2024-02-10 11:19:22 +00:00
Anthony Stirling
e1c3561997 version bump and expose ports 2024-02-10 10:29:17 +00:00
mannam11
bf8b902100 Merge branch 'main' into fixed-stamptool-wrong-filename-generaion-#757 2024-02-10 15:57:38 +05:30
Anthony Stirling
8a5883501a Merge pull request #797 from Stirling-Tools/fixes
Fixes for docker changes plus others
2024-02-10 00:33:49 +00:00
Anthony Stirling
fd8f3ce019 Merge pull request #798 from Stirling-Tools/pixeebot/fixes
Hardening suggestions for Stirling-PDF / fixes
2024-02-10 00:33:33 +00:00
Anthony Stirling
6f72096953 more fixes 2024-02-10 00:21:00 +00:00
Anthony Stirling
5a52e3d6dd other changes 2024-02-10 00:08:54 +00:00
pixeebot[bot]
23672cd18d Modernize and secure temp file creation 2024-02-10 00:08:18 +00:00
pixeebot[bot]
68c0941666 Sanitized user-provided file names in HTTP multipart uploads 2024-02-10 00:08:18 +00:00
Anthony Stirling
96e399a617 changing html and book labels 2024-02-10 00:00:07 +00:00
Anthony Stirling
22343e507d fixes 2024-02-09 23:45:18 +00:00
Anthony Stirling
8a143d139c Merge remote-tracking branch 'origin/main' into fixes 2024-02-09 23:30:25 +00:00
Anthony Stirling
15ad46fe1c book htmk 2024-02-09 23:24:25 +00:00
Anthony Stirling
2473f0d034 Update build.gradle 2024-02-09 23:22:16 +00:00
Anthony Stirling
f211eefc85 Merge pull request #624 from Zoey2936/main
switch images to alpine
2024-02-09 23:22:07 +00:00
mannam
9da88b7652 fixed wrong filename generation through stamp tool #757 2024-02-09 19:35:34 +05:30
Anthony Stirling
729c8006d2 Merge pull request #789 from mannam11/fixed_remove_pages_exception#761
Fixed remove pages un-handled exception with space in input #761
2024-02-08 17:25:17 +00:00
Anthony Stirling
0d5b790443 Merge branch 'main' into fixed_remove_pages_exception#761 2024-02-08 17:19:30 +00:00
Anthony Stirling
aa16035137 Merge pull request #787 from Stirling-Tools/fix_stamp_margins
fix: use the same margins for x and y in the stamp feature
2024-02-08 17:18:31 +00:00
mannam
41686883ee Fixed remove pages un-handled exception with space in input #761 2024-02-08 21:03:57 +05:30
Eric
2e0790c893 Merge pull request #788 from Stirling-Tools/pixeebot/fix_stamp_margins
Hardening suggestions for Stirling-PDF / fix_stamp_margins
2024-02-07 21:52:21 -05:00
pixeebot[bot]
4e937a6024 Sanitized user-provided file names in HTTP multipart uploads 2024-02-08 02:46:39 +00:00
sbplat
4af58118c9 fix: use the same margins for x and y in the stamp feature 2024-02-07 21:40:33 -05:00
Zoey
aa2ad33c1d fix libreoffice install 2024-02-07 06:15:32 +01:00
Anthony Stirling
c7005bc07f Merge pull request #780 from NeilJared/main
Updated es_ES translation (100% completed)
2024-02-06 09:40:30 +00:00
NeilJared
3f932ebec9 Update messages_es_ES.properties
Updated es_ES translation (100%)
2024-02-06 10:03:55 +01:00
Stirling-PDF-Bot
296f265391 Update 3rd Party Licenses 2024-02-06 08:39:13 +00:00
Anthony Stirling
ca8519cb10 Merge remote-tracking branch 'origin/main' into fixes 2024-02-06 00:01:15 +00:00
Anthony Stirling
734d76a3b5 test 2024-02-06 00:00:49 +00:00
Anthony Stirling
f5a39ed514 Merge pull request #776 from michelheusschen/fix/dutch-small-corrections
fix: small corrections for Dutch language
2024-02-04 18:53:04 +00:00
Michel Heusschen
96f4e5eac7 fix: small corrections for Dutch language 2024-02-04 18:08:55 +01:00
Zoey
d190ae0cf3 add @testing (3/3) 2024-01-31 21:02:22 +01:00
Zoey
bb08a63296 add @testing (2/3) 2024-01-31 21:02:22 +01:00
Zoey
3debc1b0df add @testing (1/3) 2024-01-31 21:02:22 +01:00
Zoey
e560028097 Update Dockerfile-lite 2024-01-31 21:02:22 +01:00
Zoey
5afcbdbc8b use patched libreoffice version 2024-01-31 21:02:22 +01:00
Zoey
aaaf3ffe34 fix some things 2024-01-31 21:02:22 +01:00
Zoey
b043e666ae switch images to alpine
Signed-off-by: Zoey <zoey@z0ey.de>
2024-01-31 21:02:22 +01:00
300 changed files with 26203 additions and 25087 deletions

View File

@@ -1,2 +1,5 @@
# Formatting # Formatting
5f771b785130154ed47952635b7acef371ffe0ec 5f771b785130154ed47952635b7acef371ffe0ec
# Normalize files
55d4fda01b2f39f5b7d7b4fda5214bd7ff0fd5dd

View File

@@ -1,47 +1,62 @@
# Use the base image # Main stage
FROM frooodle/stirling-pdf-base:version8 FROM alpine:3.19.1
# Copy necessary files
COPY scripts /scripts
COPY pipeline /pipeline
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto
COPY build/libs/*.jar app.jar
ARG VERSION_TAG ARG VERSION_TAG
# Set Environment Variables # Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
# PUID=1000 \ HOME=/home/stirlingpdfuser \
# PGID=1000 \ PUID=1000 \
# UMASK=022 \ PGID=1000 \
UMASK=022
# Create user and group # JDK for app
##RUN groupadd -g $PGID stirlingpdfgroup && \ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
## useradd -u $PUID -g stirlingpdfgroup -s /bin/sh stirlingpdfuser && \ echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
## mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
apk add --no-cache \
ca-certificates \
tzdata \
tini \
bash \
curl \
openjdk17-jre \
su-exec \
# Doc conversion
libreoffice@testing \
# OCR MY PDF (unpaper for descew and other advanced featues)
ocrmypdf \
tesseract-ocr-data-eng \
# CV
py3-opencv \
# python3/pip
python3 && \
wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \
# uno unoconv and HTML
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \
mv /usr/share/tessdata /usr/share/tessdata-original && \
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
fc-cache -f -v && \
chmod +x /scripts/* && \
chmod +x /scripts/init.sh && \
# User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
# Set up necessary directories and permissions
RUN mkdir -p /scripts /usr/share/fonts/opentype/noto /usr/share/tesseract-ocr /configs /logs /customFiles /pipeline /pipeline/defaultWebUIConfigs /pipeline/watchedFolders /pipeline/finishedFolders
##&& \
## chown -R stirlingpdfuser:stirlingpdfgroup /scripts /usr/share/fonts/opentype/noto /usr/share/tesseract-ocr /configs /customFiles && \
## chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/tesseract-ocr-original
# Copy necessary files
COPY ./scripts/* /scripts/
COPY ./pipeline/ /pipeline/
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
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 && chmod +x /scripts/*
##&& \
## chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
## chmod +x /scripts/init.sh
# Expose necessary ports
EXPOSE 8080 EXPOSE 8080
# Set user and run command # Set user and run command
##USER stirlingpdfuser ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
ENTRYPOINT ["/scripts/init.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"] CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

View File

@@ -1,65 +1,61 @@
# Build jbig2enc in a separate stage # use alpine
FROM bellsoft/liberica-openjdk-debian:17 FROM alpine:3.19.1
ARG VERSION_TAG ARG VERSION_TAG
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libreoffice-core \
libreoffice-common \
libreoffice-writer \
libreoffice-calc \
libreoffice-impress \
unoconv && \
rm -rf /var/lib/apt/lists/*
# Set Environment Variables # Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \ HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
# PUID=1000 \ PUID=1000 \
# PGID=1000 \ PGID=1000 \
# UMASK=022 \ 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
# Set up necessary directories and permissions
RUN mkdir -p /scripts /usr/share/fonts/opentype/noto /configs /customFiles /logs /pipeline /pipeline/defaultWebUIConfigs /pipeline/watchedFolders /pipeline/finishedFolders
# chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/fonts/opentype/noto /configs /customFiles
# Copy necessary files # Copy necessary files
COPY ./scripts/download-security-jar.sh /scripts/download-security-jar.sh COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh
COPY ./scripts/init-without-ocr.sh /scripts/init-without-ocr.sh COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
COPY ./pipeline/ /pipeline/ COPY pipeline /pipeline
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/ COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/ COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto
COPY build/libs/*.jar app.jar COPY build/libs/*.jar app.jar
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
apk add --no-cache \
ca-certificates \
tzdata \
tini \
bash \
curl \
openjdk17-jre \
su-exec \
# Doc conversion
libreoffice@testing \
# python and pip
python3 && \
wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \
# uno unoconv and HTML
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \
# Set up necessary directories and permissions
mkdir -p /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
# Set font cache and permissions # Set font cache and permissions
RUN fc-cache -f -v && \ fc-cache -f -v && \
chmod +x /scripts/init-without-ocr.sh && \ chmod +x /scripts/*.sh && \
chmod +x /scripts/download-security-jar.sh # User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
# chown stirlingpdfuser:stirlingpdfgroup /app.jar
# Expose the application port
EXPOSE 8080
# Set environment variables # Set environment variables
ENV ENDPOINTS_GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF ENV ENDPOINTS_GROUPS_TO_REMOVE=OpenCV,OCRmyPDF
ENV DOCKER_ENABLE_SECURITY=false ENV DOCKER_ENABLE_SECURITY=false
EXPOSE 8080
# Run the application # Run the application
#USER stirlingpdfuser
ENTRYPOINT ["/scripts/init-without-ocr.sh"] ENTRYPOINT ["tini", "--", "/scripts/init-without-ocr.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"] CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

View File

@@ -1,5 +1,5 @@
# Build jbig2enc in a separate stage # use alpine
FROM bellsoft/liberica-openjdk-alpine:17 FROM alpine:3.19.1
ARG VERSION_TAG ARG VERSION_TAG
@@ -7,40 +7,44 @@ ARG VERSION_TAG
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \ HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
# PUID=1000 \ PUID=1000 \
# PGID=1000 \ PGID=1000 \
# UMASK=022 \ UMASK=022
# Create user and group using Alpine's addgroup and adduser # Copy necessary files
#RUN addgroup -g $PGID stirlingpdfgroup && \ COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh
# adduser -u $PUID -G stirlingpdfgroup -s /bin/sh -D stirlingpdfuser && \ COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
# mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME COPY pipeline /pipeline
# Set up necessary directories and permissions
#RUN mkdir -p /scripts /configs /customFiles && \
# chown -R stirlingpdfuser:stirlingpdfgroup /scripts /configs /customFiles /logs /pipeline /pipeline/defaultWebUIConfigs /pipeline/watchedFolders /pipeline/finishedFolders
RUN mkdir -p /scripts /usr/share/fonts/opentype/noto /configs /customFiles
COPY ./scripts/download-security-jar.sh /scripts/download-security-jar.sh
COPY ./scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
COPY ./pipeline/ /pipeline/
COPY build/libs/*.jar app.jar COPY build/libs/*.jar app.jar
# Set font cache and permissions
#RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
RUN chmod +x /scripts/init-without-ocr.sh && \ # Set up necessary directories and permissions
chmod +x /scripts/download-security-jar.sh && \
apk add --no-cache curl
# Expose the application port RUN mkdir /configs /logs /customFiles && \
EXPOSE 8080 chmod +x /scripts/*.sh && \
apk add --no-cache \
ca-certificates \
tzdata \
tini \
bash \
curl \
su-exec \
openjdk17-jre && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
# User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /configs /customFiles /pipeline && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
# Set environment variables # Set environment variables
ENV ENDPOINTS_GROUPS_TO_REMOVE=CLI ENV ENDPOINTS_GROUPS_TO_REMOVE=CLI
ENTRYPOINT ["/scripts/init-without-ocr.sh"] EXPOSE 8080
ENTRYPOINT ["tini", "--", "/scripts/init-without-ocr.sh"]
# Run the application # Run the application
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"] CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

View File

@@ -1,43 +0,0 @@
# Main stage
FROM ubuntu:latest AS base
# JDK for app
RUN apt-get update && \
apt-get install -y --no-install-recommends \
openjdk-17-jre && \
rm -rf /var/lib/apt/lists/*
# Doc conversion
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libreoffice-core \
libreoffice-common \
libreoffice-writer \
libreoffice-calc \
libreoffice-impress \
python3-uno \
curl \
unoconv && \
rm -rf /var/lib/apt/lists/*
# OCR MY PDF (unpaper for descew and other advanced featues)
RUN apt-get update && apt-get install -y --no-install-recommends software-properties-common gnupg2 && \
add-apt-repository ppa:alex-p/tesseract-ocr5 && apt install -y --no-install-recommends tesseract-ocr && \
apt-get update && \
apt-get install -y --no-install-recommends \
ghostscript \
python3-pip \
ocrmypdf \
unpaper && \
rm -rf /var/lib/apt/lists/* && \
mv /usr/share/tesseract-ocr /usr/share/tesseract-ocr-original && \
pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir --upgrade ocrmypdf && \
pip install --no-cache-dir --upgrade pillow==10.0.1 reportlab==3.6.13 wheel==0.38.1 setuptools==65.5.1 pyjwt==2.4.0 cryptography==39.0.1
#CV and HTML
RUN pip install --no-cache-dir opencv-python-headless WeasyPrint

View File

@@ -12,7 +12,7 @@ https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/temp
and add a flag svg file to and add a flag svg file to
https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags
Any SVG flags are fine, i got most of mine from [here](https://flagicons.lipis.dev/) Any SVG flags are fine, i got most of mine from [here](https://flagicons.lipis.dev/)
If your language isnt represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia If your language isn't represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia
For example to add Polish you would add For example to add Polish you would add
@@ -32,7 +32,7 @@ Copy and rename it to messages_{your data-language-code here}.properties, in the
Then simply translate all property entries within that file and make a PR into main for others to use! Then simply translate all property entries within that file and make a PR into main for others to use!
If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but wont be able to verify the translations themselves) If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but won't be able to verify the translations themselves)

View File

@@ -2,8 +2,8 @@
This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker. This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker.
## My OCR used to work and now doesnt! ## My OCR used to work and now doesn't!
Please update your tesseract docker volume path version from 4.00 to 5 The paths have changed for the tessadata locations on new docker images, please use ``/usr/share/tessdata`` (Others should still work for backwards compatability but might not)
## How does the OCR Work ## How does the OCR Work
Stirling-PDF uses [OCRmyPDF](https://github.com/ocrmypdf/OCRmyPDF) which in turn uses tesseract for its text recognition. Stirling-PDF uses [OCRmyPDF](https://github.com/ocrmypdf/OCRmyPDF) which in turn uses tesseract for its text recognition.
@@ -21,7 +21,7 @@ Depending on your requirements, you can choose the appropriate language pack for
### Installing Language Packs ### Installing Language Packs
1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need. 1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need.
2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tesseract-ocr/5/tessdata` (Debian) or `/usr/share/tesseract/tessdata` (Fedora) 2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tessdata`
# DO NOT REMOVE EXISTING ENG.TRAINEDDATA, IT'S REQUIRED. # DO NOT REMOVE EXISTING ENG.TRAINEDDATA, IT'S REQUIRED.
@@ -37,14 +37,14 @@ services:
your_service_name: your_service_name:
image: your_docker_image_name image: your_docker_image_name
volumes: volumes:
- /location/of/trainingData:/usr/share/tesseract-ocr/5/tessdata - /location/of/trainingData:/usr/share/tessdata
``` ```
#### Docker run #### Docker run
Add the following to your existing docker run command Add the following to your existing docker run command
```bash ```bash
-v /location/of/trainingData:/usr/share/tesseract-ocr/5/tessdata -v /location/of/trainingData:/usr/share/tessdata
``` ```
#### Non-Docker #### Non-Docker

View File

@@ -65,7 +65,7 @@ sudo make install
``` ```
### Step 3: Install Additional Software ### Step 3: Install Additional Software
Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for patern recognition functionality. Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for pattern recognition functionality.
Install the following software: Install the following software:
@@ -139,7 +139,7 @@ Easiest is to use the langpacks provided by your repositories. Skip the other st
Manual: Manual:
1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need. 1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need.
2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tesseract-ocr/5/tessdata` 2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tessdata`
3. 3.
Please view [OCRmyPDF install guide](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for more info. Please view [OCRmyPDF install guide](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for more info.
**IMPORTANT:** DO NOT REMOVE EXISTING `eng.traineddata`, IT'S REQUIRED. **IMPORTANT:** DO NOT REMOVE EXISTING `eng.traineddata`, IT'S REQUIRED.
@@ -264,7 +264,7 @@ sudo systemctl restart stirlingpdf.service
Remember to set the necessary environment variables before running the project if you want to customize the application the list can be seen in the main readme. Remember to set the necessary environment variables before running the project if you want to customize the application the list can be seen in the main readme.
You can do this in the terminal by using the `export` command or -D arguements to java -jar command: You can do this in the terminal by using the `export` command or -D argument to java -jar command:
```bash ```bash
export APP_HOME_NAME="Stirling PDF" export APP_HOME_NAME="Stirling PDF"

View File

@@ -6,7 +6,7 @@
[![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/) [![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/)
[![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf) [![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf)
[![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/paypalme/froodleplex) [![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/paypalme/froodleplex)
[![Github Sponser](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle) [![Github Sponsor](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle)
[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af) [![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
@@ -110,10 +110,11 @@ Docker Run
```bash ```bash
docker run -d \ docker run -d \
-p 8080:8080 \ -p 8080:8080 \
-v /location/of/trainingData:/usr/share/tesseract-ocr/5/tessdata \ -v /location/of/trainingData:/usr/share/tessdata \
-v /location/of/extraConfigs:/configs \ -v /location/of/extraConfigs:/configs \
-v /location/of/logs:/logs \ -v /location/of/logs:/logs \
-e DOCKER_ENABLE_SECURITY=false \ -e DOCKER_ENABLE_SECURITY=false \
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
--name stirling-pdf \ --name stirling-pdf \
frooodle/s-pdf:latest frooodle/s-pdf:latest
@@ -131,12 +132,13 @@ services:
ports: ports:
- '8080:8080' - '8080:8080'
volumes: volumes:
- /location/of/trainingData:/usr/share/tesseract-ocr/5/tessdata #Required for extra OCR languages - /location/of/trainingData:/usr/share/tessdata #Required for extra OCR languages
- /location/of/extraConfigs:/configs - /location/of/extraConfigs:/configs
# - /location/of/customFiles:/customFiles/ # - /location/of/customFiles:/customFiles/
# - /location/of/logs:/logs/ # - /location/of/logs:/logs/
environment: environment:
- DOCKER_ENABLE_SECURITY=false - DOCKER_ENABLE_SECURITY=false
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
``` ```
Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "podman". Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "podman".
@@ -172,7 +174,7 @@ Stirling PDF currently supports 26!
- Hindi (हिंदी) (hi_IN) - Hindi (हिंदी) (hi_IN)
- Hungarian (Magyar) (hu_HU) - Hungarian (Magyar) (hu_HU)
- Bulgarian (Български) (bg_BG) - Bulgarian (Български) (bg_BG)
- Sebian Latin alphabet (Srpski) (sr-Latn-RS) - Sebian Latin alphabet (Srpski) (sr_LATN_RS)
## Contributing (creating issues, translations, fixing bugs, etc.) ## Contributing (creating issues, translations, fixing bugs, etc.)
@@ -228,6 +230,7 @@ metrics:
- ``SYSTEM_ROOTURIPATH`` ie set to ``/pdf-app`` to Set the application's root URI to ``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 - ``SYSTEM_CONNECTIONTIMEOUTMINUTES`` to set custom connection timeout values
- ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login) - ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login)
- ``INSTALL_BOOK_AND_ADVANCED_HTML_OPS`` to download calibre onto stirling-pdf enabling pdf to/from book and advanced html conversion
## API ## API
For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation
@@ -262,7 +265,7 @@ For API usage you must provide a header with 'X-API-Key' and the associated API
- Redact text (Via UI not just automated way) - Redact text (Via UI not just automated way)
- Add Forms - Add Forms
- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing - Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
- Fill forms mannual and automatic - Fill forms manually or automatically
### Q2: Why is my application downloading .htm files? ### Q2: Why is my application downloading .htm files?
This is an issue caused commonly by your NGINX configuration. 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 an issue caused commonly by your NGINX configuration. 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.

View File

@@ -12,7 +12,7 @@ plugins {
import com.github.jk1.license.render.* import com.github.jk1.license.render.*
group = 'stirling.software' group = 'stirling.software'
version = '0.20.2' version = '0.22.0'
sourceCompatibility = '17' sourceCompatibility = '17'
repositories { repositories {
@@ -89,7 +89,7 @@ dependencies {
//security updates //security updates
implementation 'ch.qos.logback:logback-classic:1.4.14' implementation 'ch.qos.logback:logback-classic:1.4.14'
implementation 'ch.qos.logback:logback-core:1.4.14' implementation 'ch.qos.logback:logback-core:1.4.14'
implementation 'org.springframework:spring-webmvc:6.1.2' implementation 'org.springframework:spring-webmvc:6.1.3'
implementation("io.github.pixee:java-security-toolkit:1.1.2") implementation("io.github.pixee:java-security-toolkit:1.1.2")
@@ -150,7 +150,7 @@ dependencies {
implementation 'org.bouncycastle:bcprov-jdk18on:1.77' implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77' implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.2' implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.2'
implementation 'io.micrometer:micrometer-core:1.12.2' implementation 'io.micrometer:micrometer-core:1.12.3'
implementation group: 'com.google.zxing', name: 'core', version: '3.5.2' implementation group: 'com.google.zxing', name: 'core', version: '3.5.2'
// https://mvnrepository.com/artifact/org.commonmark/commonmark // https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation 'org.commonmark:commonmark:0.21.0' implementation 'org.commonmark:commonmark:0.21.0'

View File

@@ -1,5 +1,5 @@
apiVersion: v2 apiVersion: v2
appVersion: 0.14.2 appVersion: 0.20.2
description: locally hosted web application that allows you to perform various operations on PDF files description: locally hosted web application that allows you to perform various operations on PDF files
home: https://github.com/Stirling-Tools/Stirling-PDF home: https://github.com/Stirling-Tools/Stirling-PDF
keywords: keywords:

View File

@@ -16,11 +16,11 @@ commonLabels: {}
# team_name: dev # team_name: dev
envs: [] envs: []
# - name: PP_HOME_NAME # - name: UI_APP_NAME
# value: "Stirling PDF" # value: "Stirling PDF"
# - name: APP_HOME_DESCRIPTION # - name: UI_HOME_DESCRIPTION
# value: "Your locally hosted one-stop-shop for all your PDF needs." # value: "Your locally hosted one-stop-shop for all your PDF needs."
# - name: APP_NAVBAR_NAME # - name: UI_APP_NAVBAR_NAME
# value: "Stirling PDF" # value: "Stirling PDF"
# - name: ALLOW_GOOGLE_VISIBILITY # - name: ALLOW_GOOGLE_VISIBILITY
# value: "true" # value: "true"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -1,310 +1,110 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg <svg
width="99.537987mm"
height="95.209366mm"
viewBox="0 0 99.537987 95.209366"
version="1.1" version="1.1"
id="svg745" id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 512 512"
style="enable-background:new 0 0 512 512;"
xml:space="preserve" xml:space="preserve"
inkscape:version="1.2.1 (9c6d41e4, 2022-07-14)" sodipodi:docname="favicon.svg"
sodipodi:docname="stirling.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
inkscape:export-filename="stirling.png" inkscape:export-filename="favicon.png"
inkscape:export-xdpi="80" inkscape:export-xdpi="96"
inkscape:export-ydpi="80" inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview xmlns:svg="http://www.w3.org/2000/svg"><defs
id="namedview747" id="defs173">
<linearGradient
id="XMLID_5_"
gradientUnits="userSpaceOnUse"
x1="304.496"
y1="422.9102"
x2="316.036"
y2="326.2626">
<stop
offset="0"
style="stop-color:#DCF1F3"
id="stop156" />
<stop
offset="1"
style="stop-color:#C2C2C9"
id="stop158" />
</linearGradient>
</defs><sodipodi:namedview
id="namedview171"
pagecolor="#ffffff" pagecolor="#ffffff"
bordercolor="#666666" bordercolor="#000000"
borderopacity="1.0" borderopacity="0.25"
inkscape:showpageshadow="2" inkscape:showpageshadow="2"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0" inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false" showgrid="false"
inkscape:zoom="0.914906" inkscape:zoom="1.4142136"
inkscape:cx="184.17193" inkscape:cx="219.91021"
inkscape:cy="509.88845" inkscape:cy="232.63813"
inkscape:window-width="2293" inkscape:window-width="3840"
inkscape:window-height="1387" inkscape:window-height="2054"
inkscape:window-x="122" inkscape:window-x="2869"
inkscape:window-y="25" inkscape:window-y="-11"
inkscape:window-maximized="0" inkscape:window-maximized="1"
inkscape:current-layer="svg745" /><defs inkscape:current-layer="XMLID_4_" />
id="defs742"><linearGradient <style
inkscape:collect="always" type="text/css"
id="linearGradient72198"><stop id="style150">
style="stop-color:#ccd6d7;stop-opacity:1;" .st0{fill:#FFFFFF;}
.st1{fill:#C02223;}
.st2{fill:#882425;}
.st3{fill:url(#XMLID_5_);}
.st4{fill:url(#XMLID_7_);}
</style>
<g
id="XMLID_4_">
<path
id="XMLID_131_"
class="st1"
d="M 347.01402,14.355825 98.978019,69.02261 C 73.825483,74.547445 55.942464,96.792175 55.942464,122.52628 v 315.06096 c 0,22.39012 16.719895,41.14548 38.819234,43.76251 L 224.8861,498.36042 339.48636,384.26465 455.76603,265.15425 453.73057,84.870162 C 453.43979,62.916214 433.08513,46.632491 411.71274,51.284984 l -28.78729,6.251786 0.14539,-13.666697 C 383.36162,24.678542 365.62399,10.284894 347.01402,14.355825 Z"
sodipodi:nodetypes="ccssccccccccc"
style="stroke-width:1.45391" /><path
id="XMLID_117_"
class="st2"
d="m 383.21622,57.53677 v 285.8375 L 456.05681,265.00885 454.02135,78.763767 C 453.87595,59.863016 436.28372,45.905539 417.81914,49.97647 Z"
style="stroke-width:1.45391" /><polygon
id="XMLID_18_"
class="st3"
points="234.7,422.6 368.5,387.7 393.5,262.2 "
style="fill:url(#XMLID_5_)"
transform="matrix(1.4556308,0,0,1.4548265,-116.73161,-116.45231)" />
<linearGradient
id="XMLID_7_"
gradientUnits="userSpaceOnUse"
x1="223.0838"
y1="372.7559"
x2="241.4174"
y2="114.557"
gradientTransform="matrix(1.4539039,0,0,1.4539039,-116.19976,-116.20474)">
<stop
offset="0" offset="0"
id="stop72194" /><stop style="stop-color:#DCF1F3"
style="stop-color:#0f3a3f;stop-opacity:1;" id="stop163" />
<stop
offset="1" offset="1"
id="stop72196" /></linearGradient><linearGradient style="stop-color:#C2C2C9"
inkscape:collect="always" id="stop165" />
id="linearGradient71928"><stop </linearGradient>
style="stop-color:#4b0005;stop-opacity:1;" <path
offset="0" id="XMLID_6_"
id="stop71924" /><stop class="st4"
style="stop-color:#8f000c;stop-opacity:1;" d="m 282.89686,214.84917 c 0,0 -22.24473,-28.93269 -38.67384,-36.78377 -10.46811,-4.94327 -26.02489,-6.83335 -38.23768,-0.72695 -18.02841,9.0142 -19.91848,34.31213 -3.34397,44.34406 3.92553,2.47165 9.15959,4.50711 15.99294,6.10641 36.63838,8.43264 97.12077,25.87949 89.70587,96.10304 0,0 -4.21633,65.86185 -73.56753,73.42215 -12.2128,1.30851 -24.57098,0.43617 -36.493,-2.32625 -16.42911,-3.63476 -45.50719,-11.04967 -59.75545,-19.91849 l -2.61703,-75.16682 h 6.97875 c 0,0 13.81208,33.43978 53.06749,49.57812 7.26952,2.90781 15.26599,4.07093 22.97168,2.90781 9.74116,-1.45391 21.22699,-6.68796 25.87949,-22.53551 0,0 7.85108,-23.11707 -32.85823,-35.76604 -32.56744,-10.17733 -63.24481,-20.64543 -75.89378,-54.95757 -5.961,-16.28371 -6.97874,-34.31212 -2.90781,-51.61358 5.37944,-22.53551 20.79082,-54.23062 64.40794,-67.89732 0,0 57.28381,-15.55677 96.53922,5.52484 l -1.74468,89.70587 z"
offset="1" style="fill:url(#XMLID_7_);stroke-width:1.45391" />
id="stop71926" /></linearGradient><linearGradient </g>
inkscape:collect="always" </svg>
id="linearGradient71920"><stop
style="stop-color:#4b0005;stop-opacity:1;"
offset="0"
id="stop71916" /><stop
style="stop-color:#8f000c;stop-opacity:1;"
offset="1"
id="stop71918" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient69598"><stop
style="stop-color:#6a0007;stop-opacity:1;"
offset="0"
id="stop69594" /><stop
style="stop-color:#b8000f;stop-opacity:1;"
offset="1"
id="stop69596" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient46361"><stop
style="stop-color:#f7f6f8;stop-opacity:1;"
offset="0"
id="stop46359" /><stop
style="stop-color:#b7b7b5;stop-opacity:1;"
offset="1"
id="stop46357" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient40554"><stop
style="stop-color:#f4f2f4;stop-opacity:1;"
offset="0"
id="stop40550" /><stop
style="stop-color:#57767b;stop-opacity:1;"
offset="1"
id="stop40552" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient39095"><stop
style="stop-color:#285459;stop-opacity:1;"
offset="0"
id="stop39093" /><stop
style="stop-color:#a6b6af;stop-opacity:1;"
offset="1"
id="stop39091" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient36672"><stop
style="stop-color:#da453f;stop-opacity:1;"
offset="0"
id="stop36668" /><stop
style="stop-color:#a60008;stop-opacity:1;"
offset="1"
id="stop36670" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient19524"><stop
style="stop-color:#3a4b4f;stop-opacity:1;"
offset="0"
id="stop19522" /><stop
style="stop-color:#617979;stop-opacity:0.97461927;"
offset="1"
id="stop19520" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient17996"><stop
style="stop-color:#401016;stop-opacity:1;"
offset="0"
id="stop17994" /><stop
style="stop-color:#761f19;stop-opacity:1;"
offset="1"
id="stop17992" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient15569"><stop
style="stop-color:#8ea8ad;stop-opacity:1;"
offset="0"
id="stop15565" /><stop
style="stop-color:#e9e7eb;stop-opacity:1;"
offset="1"
id="stop15567" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient15557"><stop
style="stop-color:#9b0e11;stop-opacity:1;"
offset="0"
id="stop15553" /><stop
style="stop-color:#370707;stop-opacity:1;"
offset="1"
id="stop15555" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15557"
id="linearGradient15559"
x1="120.06672"
y1="63.25761"
x2="135.16347"
y2="78.078682"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15569"
id="linearGradient15571"
x1="127.97037"
y1="101.66144"
x2="133.88971"
y2="104.77026"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient17996"
id="linearGradient17998"
x1="117.9284"
y1="86.055084"
x2="130.67392"
y2="76.945541"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient19524"
id="linearGradient19528"
x1="130.98172"
y1="82.402977"
x2="135.72115"
y2="86.45166"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient36672"
id="linearGradient36674"
x1="63.797714"
y1="74.81752"
x2="96.636673"
y2="120.29293"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient39095"
id="linearGradient39097"
x1="120.54506"
y1="124.76902"
x2="128.04152"
y2="126.0704"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient40554"
id="linearGradient40556"
x1="113.84585"
y1="114.04285"
x2="119.65858"
y2="128.50244"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient46361"
id="linearGradient46363"
x1="73.993439"
y1="114.13906"
x2="94.845322"
y2="71.247383"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient69598"
id="linearGradient69600"
x1="95.854446"
y1="114.66749"
x2="103.77842"
y2="120.1887"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient71920"
id="linearGradient71922"
x1="98.580376"
y1="87.186958"
x2="118.09738"
y2="101.19449"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient71928"
id="linearGradient71930"
x1="78.278267"
y1="97.433273"
x2="92.313202"
y2="104.33479"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient72198"
id="linearGradient72200"
x1="125.76636"
y1="138.46817"
x2="123.3327"
y2="126.03291"
gradientUnits="userSpaceOnUse" /></defs><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="background"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-51.420144,-44.470286)"><rect
style="display:inline;fill:#ccd6d7;fill-opacity:1;stroke:none;stroke-width:4.13755;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.2"
id="rect72067"
width="99.481979"
height="94.999512"
x="51.476147"
y="44.680138" /></g><g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="shadow"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-51.420144,-44.470286)"><path
style="display:inline;fill:url(#linearGradient72200);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 84.146049,134.73858 c 0,0 11.721038,2.48294 17.938661,2.91673 6.21763,0.43378 14.75251,0.59994 22.41237,-0.43379 8.01008,-1.081 13.19907,-2.22733 14.50043,-2.66112 1.30136,-0.43379 4.00784,-1.24297 4.15244,-2.25514 0.1446,-1.01217 -3.4703,-2.74733 -6.21763,-3.32571 -2.74732,-0.57838 -12.72444,-1.44596 -14.89337,-1.44596 -2.16894,0 -37.892901,7.20499 -37.892901,7.20499 z"
id="path72192"
sodipodi:nodetypes="cssssssc" /></g><g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Origami"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-51.420144,-44.470286)"><path
style="display:inline;fill:url(#linearGradient40556);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 84.460552,134.86721 35.165798,-6.85679 16.15467,-42.7383 z"
id="path960"
sodipodi:nodetypes="cccc" /><path
style="fill:url(#linearGradient15571);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 135.71493,85.428056 0.3984,45.049024 -9.66213,-20.46173 z"
id="path964"
sodipodi:nodetypes="cccc" /><path
style="display:inline;fill:url(#linearGradient39097);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 119.60518,128.00293 16.5337,2.48693 -9.68769,-20.5512 z"
id="path966"
sodipodi:nodetypes="cccc" /><path
style="display:inline;fill:url(#linearGradient15559);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 118.42209,57.022622 12.70423,-2.766809 -0.0785,25.087175 -12.43878,-13.376518 z"
id="path968"
sodipodi:nodetypes="ccccc" /><path
style="display:inline;fill:url(#linearGradient19528);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 135.72114,85.386768 -4.84219,-6.459493 0.0305,11.126604 z"
id="path970"
sodipodi:nodetypes="cccc" /><path
style="display:inline;fill:url(#linearGradient17998);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 119.10273,65.682415 11.96883,13.44935 -0.0899,10.819868 -11.88577,11.430427 z"
id="path972"
sodipodi:nodetypes="ccccc" /><path
style="display:inline;fill:url(#linearGradient36674);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 62.145635,130.15618 62.043392,65.435258 c 0,0 0.179321,-2.778132 1.89516,-4.036097 1.874923,-1.374597 4.341768,-1.894096 4.341768,-1.894096 l 50.91788,-11.349167 -0.0113,53.144272 -34.733274,33.56547 z"
id="path958"
sodipodi:nodetypes="ccsccccc" /></g><g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Letter"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-51.420144,-44.470286)"><path
style="display:inline;fill:url(#linearGradient69600);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 94.780881,91.406803 16.870379,17.074877 -23.723345,23.00249 -18.122131,-17.99816 5.497473,-2.80607 18.404054,-0.0511 2.35163,-8.23071 z"
id="path54894"
sodipodi:nodetypes="cccccccc" /><path
style="display:inline;fill:url(#linearGradient71930);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 72.440405,92.224764 16.15467,15.745686 4.089788,-6.79927 z"
id="path54892" /><path
style="display:inline;fill:url(#linearGradient71922);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 95.138739,84.965385 1.124691,-14.109776 22.92453,22.286787 0.008,8.164604 -3.28863,3.16649 z"
id="path54890"
sodipodi:nodetypes="cccccc"
inkscape:label="path54890" /><path
style="display:inline;fill:url(#linearGradient46363);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 95.138739,84.965385 h 1.226936 l -0.05112,-14.109776 c 0,0 -5.776827,-3.220709 -12.167126,-2.40275 -6.390296,0.817957 -8.151582,2.1248 -10.58233,4.396523 -1.90229,1.777838 -2.913974,3.527446 -3.987546,7.157132 -0.512646,1.733226 -0.281963,5.988892 0.613471,8.537436 0.664591,1.891528 2.453873,4.294281 4.958868,6.134686 2.662335,1.956002 8.281825,3.527443 8.281825,3.527443 0,0 5.134614,1.887351 5.572338,4.294281 0.308137,1.69437 -0.102243,3.22071 -1.635914,4.95887 -1.258314,1.42609 -3.62969,1.99377 -6.288054,1.07357 -2.658364,-0.92021 -6.139514,-3.85065 -7.106009,-4.90775 -0.817958,-0.89464 -2.820665,-3.06173 -2.890231,-4.294021 -0.01209,-0.214205 -1.229505,-0.0963 -1.229505,-0.0963 l -0.0723,14.256941 5.879073,2.24938 c 0,0 5.214483,1.78929 8.946415,1.43143 3.731934,-0.35786 7.617235,-0.51122 11.604778,-5.16336 3.987542,-4.65213 3.680812,-12.831715 2.147141,-15.899056 -1.533673,-3.067344 -3.561212,-6.138812 -10.480087,-8.281826 -5.776829,-1.789283 -7.872846,-3.01622 -8.128458,-4.396524 -0.255611,-1.380305 0.0091,-4.253646 2.760607,-5.214481 3.220711,-1.124693 5.623462,-0.05112 7.05489,1.12469 1.431425,1.175817 5.572339,5.623462 5.572339,5.623462 z"
id="path46355"
sodipodi:nodetypes="cccssssscssssscccssssssscc" /></g></svg>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -15,7 +15,7 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:

View File

@@ -15,7 +15,7 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:

View File

@@ -15,7 +15,7 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:

View File

@@ -15,7 +15,7 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:

View File

@@ -6,7 +6,8 @@
"parameters": { "parameters": {
"horizontalDivisions": 2, "horizontalDivisions": 2,
"verticalDivisions": 2, "verticalDivisions": 2,
"fileInput": "automated" "fileInput": "automated",
"merge": false
} }
}, },
{ {

View File

@@ -1,37 +0,0 @@
import cv2
import sys
import argparse
import numpy as np
def is_blank_image(image_path, threshold=10, white_percent=99, white_value=255, blur_size=5):
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if image is None:
print(f"Error: Unable to read the image file: {image_path}")
return False
# Apply Gaussian blur to reduce noise
blurred_image = cv2.GaussianBlur(image, (blur_size, blur_size), 0)
_, thresholded_image = cv2.threshold(blurred_image, white_value - threshold, white_value, cv2.THRESH_BINARY)
# Calculate the percentage of white pixels in the thresholded image
white_pixels = np.sum(thresholded_image == white_value)
white_pixel_percentage = (white_pixels / thresholded_image.size) * 100
print(f"Page has white pixel percent of {white_pixel_percentage}")
return white_pixel_percentage >= white_percent
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Detect if an image is considered blank or not.')
parser.add_argument('image_path', help='The path to the image file.')
parser.add_argument('-t', '--threshold', type=int, default=10, help='Threshold for determining white pixels. The default value is 10.')
parser.add_argument('-w', '--white_percent', type=float, default=99, help='The percentage of white pixels for an image to be considered blank. The default value is 99.')
args = parser.parse_args()
blank = is_blank_image(args.image_path, args.threshold, args.white_percent)
# Return code 1: The image is considered blank.
# Return code 0: The image is not considered blank.
sys.exit(int(blank))

View File

@@ -14,6 +14,8 @@ if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
if [ $? -eq 0 ]; then # checks if curl was successful if [ $? -eq 0 ]; then # checks if curl was successful
rm -f app.jar rm -f app.jar
ln -s app-security.jar app.jar ln -s app-security.jar app.jar
chown stirlingpdfuser:stirlingpdfgroup app.jar
chmod 755 app.jar
fi fi
fi fi
fi fi

View File

@@ -1,6 +1,24 @@
#!/bin/sh #!/bin/sh
# Update the user and group IDs as per environment variables
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
usermod -o -u "$PUID" stirlingpdfuser
fi
if [ ! -z "$PGID" ] && [ "$PGID" != "$(id -g stirlingpdfgroup)" ]; then
groupmod -o -g "$PGID" stirlingpdfgroup
fi
umask "$UMASK"
echo "Setting permissions and ownership for necessary directories..."
chown -R stirlingpdfuser:stirlingpdfgroup /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
apk add --no-cache calibre@testing
fi
/scripts/download-security-jar.sh /scripts/download-security-jar.sh
# Run the main command # Run the main command
exec "$@" exec su-exec stirlingpdfuser "$@"

View File

@@ -2,25 +2,57 @@
# Copy the original tesseract-ocr files to the volume directory without overwriting existing files # Copy the original tesseract-ocr files to the volume directory without overwriting existing files
echo "Copying original files without overwriting existing files" echo "Copying original files without overwriting existing files"
mkdir -p /usr/share/tesseract-ocr mkdir -p /usr/share/tessdata
cp -rn /usr/share/tesseract-ocr-original/* /usr/share/tesseract-ocr cp -rn /usr/share/tessdata-original/* /usr/share/tessdata
if [ -d /usr/share/tesseract-ocr/4.00/tessdata ]; then if [ -d /usr/share/tesseract-ocr/4.00/tessdata ]; then
cp -r /usr/share/tesseract-ocr/4.00/tessdata/* /usr/share/tesseract-ocr/5/tessdata/ || true; cp -r /usr/share/tesseract-ocr/4.00/tessdata/* /usr/share/tessdata || true;
fi fi
if [ -d /usr/share/tesseract-ocr/5/tessdata ]; then
cp -r /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata || true;
fi
# Update the user and group IDs as per environment variables
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
usermod -o -u "$PUID" stirlingpdfuser
fi
if [ ! -z "$PGID" ] && [ "$PGID" != "$(id -g stirlingpdfgroup)" ]; then
groupmod -o -g "$PGID" stirlingpdfgroup
fi
umask "$UMASK"
echo "Setting permissions and ownership for necessary directories..."
chown -R stirlingpdfuser:stirlingpdfgroup /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles
# Check if TESSERACT_LANGS environment variable is set and is not empty # Check if TESSERACT_LANGS environment variable is set and is not empty
if [[ -n "$TESSERACT_LANGS" ]]; then if [[ -n "$TESSERACT_LANGS" ]]; then
# Convert comma-separated values to a space-separated list # Convert comma-separated values to a space-separated list
LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ') LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ')
pattern='^[a-zA-Z]{2,4}(_[a-zA-Z]{2,4})?$'
# Install each language pack # Install each language pack
for LANG in $LANGS; do for LANG in $LANGS; do
apt-get install -y "tesseract-ocr-$LANG" if [[ $LANG =~ $pattern ]]; then
apk add --no-cache "tesseract-ocr-data-$LANG"
else
echo "Skipping invalid language code"
fi
done done
fi fi
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
apk add --no-cache calibre@testing
fi
/scripts/download-security-jar.sh /scripts/download-security-jar.sh
# Run the main command # Run the main command and switch to stirling user for rest of run
exec "$@" exec su-exec stirlingpdfuser "$@"

View File

@@ -1,12 +1,13 @@
package stirling.software.SPDF; package stirling.software.SPDF;
import io.github.pixee.security.SystemCommand;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import io.github.pixee.security.SystemCommand;
public class LibreOfficeListener { public class LibreOfficeListener {
private static final long ACTIVITY_TIMEOUT = 20 * 60 * 1000; // 20 minutes private static final long ACTIVITY_TIMEOUT = 20 * 60 * 1000; // 20 minutes

View File

@@ -1,26 +1,43 @@
package stirling.software.SPDF; package stirling.software.SPDF;
import io.github.pixee.security.SystemCommand; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Collections; import java.util.Collections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import io.github.pixee.security.SystemCommand;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import stirling.software.SPDF.config.ConfigInitializer; import stirling.software.SPDF.config.ConfigInitializer;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.model.ApplicationProperties;
@SpringBootApplication @SpringBootApplication
@EnableScheduling @EnableScheduling
public class SPdfApplication { public class SPdfApplication {
private static final Logger logger = LoggerFactory.getLogger(SPdfApplication.class);
@Autowired private Environment env; @Autowired private Environment env;
@Autowired ApplicationProperties applicationProperties;
private static String serverPortStatic;
@Value("${server.port:8080}")
public void setServerPortStatic(String port) {
SPdfApplication.serverPortStatic = port;
}
@PostConstruct @PostConstruct
public void init() { public void init() {
// Check if the BROWSER_OPEN environment variable is set to true // Check if the BROWSER_OPEN environment variable is set to true
@@ -29,7 +46,7 @@ public class SPdfApplication {
if (browserOpen) { if (browserOpen) {
try { try {
String url = "http://localhost:" + getPort(); String url = "http://localhost:" + getNonStaticPort();
String os = System.getProperty("os.name").toLowerCase(); String os = System.getProperty("os.name").toLowerCase();
Runtime rt = Runtime.getRuntime(); Runtime rt = Runtime.getRuntime();
@@ -38,12 +55,13 @@ public class SPdfApplication {
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url); SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("Error opening browser: {}", e.getMessage());
} }
} }
logger.info("Running configs {}", applicationProperties.toString());
} }
public static void main(String[] args) { public static void main(String[] args) throws IOException, InterruptedException {
SpringApplication app = new SpringApplication(SPdfApplication.class); SpringApplication app = new SpringApplication(SPdfApplication.class);
app.addInitializers(new ConfigInitializer()); app.addInitializers(new ConfigInitializer());
if (Files.exists(Paths.get("configs/settings.yml"))) { if (Files.exists(Paths.get("configs/settings.yml"))) {
@@ -51,7 +69,7 @@ public class SPdfApplication {
Collections.singletonMap( Collections.singletonMap(
"spring.config.additional-location", "file:configs/settings.yml")); "spring.config.additional-location", "file:configs/settings.yml"));
} else { } else {
System.out.println( logger.warn(
"External configuration file 'configs/settings.yml' does not exist. Using default configuration and environment configuration instead."); "External configuration file 'configs/settings.yml' does not exist. Using default configuration and environment configuration instead.");
} }
app.run(args); app.run(args);
@@ -59,24 +77,30 @@ public class SPdfApplication {
try { try {
Thread.sleep(1000); Thread.sleep(1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// TODO Auto-generated catch block Thread.currentThread().interrupt();
e.printStackTrace(); throw new RuntimeException("Thread interrupted while sleeping", e);
} }
GeneralUtils.createDir("customFiles/static/"); try {
GeneralUtils.createDir("customFiles/templates/"); Files.createDirectories(Path.of("customFiles/static/"));
Files.createDirectories(Path.of("customFiles/templates/"));
System.out.println("Stirling-PDF Started."); } catch (Exception e) {
logger.error("Error creating directories: {}", e.getMessage());
String url = "http://localhost:" + getPort(); }
System.out.println("Navigate to " + url); printStartupLogs();
} }
public static String getPort() { private static void printStartupLogs() {
String port = System.getProperty("local.server.port"); logger.info("Stirling-PDF Started.");
if (port == null || port.isEmpty()) { String url = "http://localhost:" + getStaticPort();
port = "8080"; logger.info("Navigate to {}", url);
} }
return port;
public static String getStaticPort() {
return serverPortStatic;
}
public String getNonStaticPort() {
return serverPortStatic;
} }
} }

View File

@@ -77,16 +77,12 @@ public class AppConfig {
return Files.exists(Paths.get("/.dockerenv")); return Files.exists(Paths.get("/.dockerenv"));
} }
@Bean(name = "bookFormatsInstalled") @Bean(name = "bookAndHtmlFormatsInstalled")
public boolean bookFormatsInstalled() { public boolean bookAndHtmlFormatsInstalled() {
return applicationProperties.getSystem().getCustomApplications().isInstallBookFormats(); String installOps = System.getProperty("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
if (installOps == null) {
installOps = System.getenv("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
} }
return "true".equalsIgnoreCase(installOps);
@Bean(name = "htmlFormatsInstalled")
public boolean htmlFormatsInstalled() {
return applicationProperties
.getSystem()
.getCustomApplications()
.isInstallAdvancedHtmlToPDF();
} }
} }

View File

@@ -79,6 +79,16 @@ public class ConfigInitializer
return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : ""; return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : "";
}; };
Function<String, Integer> getIndentationLevel =
line -> {
int count = 0;
for (char ch : line.toCharArray()) {
if (ch == ' ') count++;
else break;
}
return count;
};
Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet()); Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet());
for (String line : templateLines) { for (String line : templateLines) {
@@ -134,10 +144,77 @@ public class ConfigInitializer
.map(extractKey) .map(extractKey)
.anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey)); .anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey));
if (!isPresentInTemplate && !isCommented.apply(userLine)) { if (!isPresentInTemplate && !isCommented.apply(userLine)) {
if (!childOfTemplateEntry(
isCommented,
extractKey,
getIndentationLevel,
userLines,
userLine,
templateLines)) {
// check if userLine is a child of a entry within templateLines or not, if child
// of parent in templateLines then dont add to mergedLines, if anything else
// then add
mergedLines.add(userLine); mergedLines.add(userLine);
} }
} }
}
Files.write(outputPath, mergedLines, StandardCharsets.UTF_8); Files.write(outputPath, mergedLines, StandardCharsets.UTF_8);
} }
// New method to check if a userLine is a child of an entry in templateLines
boolean childOfTemplateEntry(
Function<String, Boolean> isCommented,
Function<String, String> extractKey,
Function<String, Integer> getIndentationLevel,
List<String> userLines,
String userLine,
List<String> templateLines) {
String userKey = extractKey.apply(userLine).trim();
int userIndentation = getIndentationLevel.apply(userLine);
// Start by assuming the line is not a child of an entry in templateLines
boolean isChild = false;
// Iterate backwards through userLines from the current line to find any parent
for (int i = userLines.indexOf(userLine) - 1; i >= 0; i--) {
String potentialParentLine = userLines.get(i);
int parentIndentation = getIndentationLevel.apply(potentialParentLine);
// Check if we've reached a potential parent based on indentation
if (parentIndentation < userIndentation) {
String parentKey = extractKey.apply(potentialParentLine).trim();
// Now, check if this potential parent or any of its parents exist in templateLines
boolean parentExistsInTemplate =
templateLines.stream()
.filter(line -> !isCommented.apply(line)) // Skip commented lines
.anyMatch(
templateLine -> {
String templateKey =
extractKey.apply(templateLine).trim();
return parentKey.equalsIgnoreCase(templateKey);
});
if (!parentExistsInTemplate) {
// If the parent does not exist in template, check the next level parent
userIndentation =
parentIndentation; // Update userIndentation to the parent's indentation
// for next iteration
if (parentIndentation == 0) {
// If we've reached the top-level parent and it's not in template, the
// original line is considered not a child
isChild = false;
break;
}
} else {
// If any parent exists in template, the original line is considered a child
isChild = true;
break;
}
}
}
return isChild; // Return true if the line is not a child of any entry in templateLines
}
} }

View File

@@ -16,7 +16,7 @@ import org.springframework.stereotype.Service;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
@Service @Service
@DependsOn({"bookFormatsInstalled"}) @DependsOn({"bookAndHtmlFormatsInstalled"})
public class EndpointConfiguration { public class EndpointConfiguration {
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class); private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>(); private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
@@ -24,14 +24,14 @@ public class EndpointConfiguration {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private boolean bookFormatsInstalled; private boolean bookAndHtmlFormatsInstalled;
@Autowired @Autowired
public EndpointConfiguration( public EndpointConfiguration(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@Qualifier("bookFormatsInstalled") boolean bookFormatsInstalled) { @Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.bookFormatsInstalled = bookFormatsInstalled; this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
init(); init();
processEnvironmentConfigs(); processEnvironmentConfigs();
} }
@@ -140,7 +140,6 @@ public class EndpointConfiguration {
// CLI // CLI
addEndpointToGroup("CLI", "compress-pdf"); addEndpointToGroup("CLI", "compress-pdf");
addEndpointToGroup("CLI", "extract-image-scans"); addEndpointToGroup("CLI", "extract-image-scans");
addEndpointToGroup("CLI", "remove-blanks");
addEndpointToGroup("CLI", "repair"); addEndpointToGroup("CLI", "repair");
addEndpointToGroup("CLI", "pdf-to-pdfa"); addEndpointToGroup("CLI", "pdf-to-pdfa");
addEndpointToGroup("CLI", "file-to-pdf"); addEndpointToGroup("CLI", "file-to-pdf");
@@ -218,6 +217,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "split-by-size-or-count"); addEndpointToGroup("Java", "split-by-size-or-count");
addEndpointToGroup("Java", "overlay-pdf"); addEndpointToGroup("Java", "overlay-pdf");
addEndpointToGroup("Java", "split-pdf-by-sections"); addEndpointToGroup("Java", "split-pdf-by-sections");
addEndpointToGroup("Java", "remove-blanks");
// Javascript // Javascript
addEndpointToGroup("Javascript", "pdf-organizer"); addEndpointToGroup("Javascript", "pdf-organizer");
@@ -229,7 +229,7 @@ public class EndpointConfiguration {
private void processEnvironmentConfigs() { private void processEnvironmentConfigs() {
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove(); List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove(); List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
if (!bookFormatsInstalled) { if (!bookAndHtmlFormatsInstalled) {
groupsToRemove.add("Calibre"); groupsToRemove.add("Calibre");
} }
if (endpointsToRemove != null) { if (endpointsToRemove != null) {

View File

@@ -1,98 +0,0 @@
package stirling.software.SPDF.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
@Component
public class PostStartupProcesses {
@Autowired ApplicationProperties applicationProperties;
@Autowired
@Qualifier("RunningInDocker")
private boolean runningInDocker;
@Autowired
@Qualifier("bookFormatsInstalled")
private boolean bookFormatsInstalled;
@Autowired
@Qualifier("htmlFormatsInstalled")
private boolean htmlFormatsInstalled;
private static final Logger logger = LoggerFactory.getLogger(PostStartupProcesses.class);
@PostConstruct
public void runInstallCommandBasedOnEnvironment() throws IOException, InterruptedException {
List<List<String>> commands = new ArrayList<>();
// Checking for DOCKER_INSTALL_BOOK_FORMATS environment variable
if (bookFormatsInstalled) {
List<String> tmpList = new ArrayList<>();
// Set up the timezone configuration commands
tmpList.addAll(
Arrays.asList(
"sh",
"-c",
"echo 'tzdata tzdata/Areas select Europe' | debconf-set-selections; "
+ "echo 'tzdata tzdata/Zones/Europe select Berlin' | debconf-set-selections"));
commands.add(tmpList);
// Install calibre with DEBIAN_FRONTEND set to noninteractive
tmpList = new ArrayList<>();
tmpList.addAll(
Arrays.asList(
"sh",
"-c",
"DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends calibre"));
commands.add(tmpList);
}
// Checking for DOCKER_INSTALL_HTML_FORMATS environment variable
if (htmlFormatsInstalled) {
List<String> tmpList = new ArrayList<>();
// Add -y flag for automatic yes to prompts and --no-install-recommends to reduce size
tmpList.addAll(
Arrays.asList(
"apt-get", "install", "wkhtmltopdf", "-y", "--no-install-recommends"));
commands.add(tmpList);
}
if (!commands.isEmpty()) {
// Run the command
if (runningInDocker) {
List<String> tmpList = new ArrayList<>();
tmpList.addAll(Arrays.asList("apt-get", "update"));
commands.add(0, tmpList);
for (List<String> list : commands) {
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.INSTALL_APP, true)
.runCommandWithOutputHandling(list);
logger.info("RC for app installs {}", returnCode.getRc());
}
} else {
logger.info(
"Not running inside Docker so skipping automated install process with command.");
}
} else {
if (runningInDocker) {
logger.info("No custom apps to install.");
}
}
}
}

View File

@@ -1,6 +1,7 @@
package stirling.software.SPDF.config.security; package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
@@ -12,15 +13,19 @@ import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.model.User;
@Component @Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Autowired private final LoginAttemptService loginAttemptService; @Autowired private final LoginAttemptService loginAttemptService;
@Autowired @Autowired private final UserService userService; // Inject the UserService
public CustomAuthenticationFailureHandler(LoginAttemptService loginAttemptService) {
public CustomAuthenticationFailureHandler(
LoginAttemptService loginAttemptService, UserService userService) {
this.loginAttemptService = loginAttemptService; this.loginAttemptService = loginAttemptService;
this.userService = userService;
} }
@Override @Override
@@ -33,17 +38,28 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
logger.error("Failed login attempt from IP: " + ip); logger.error("Failed login attempt from IP: " + ip);
String username = request.getParameter("username"); String username = request.getParameter("username");
if (!isDemoUser(username)) {
if (loginAttemptService.loginAttemptCheck(username)) { if (loginAttemptService.loginAttemptCheck(username)) {
setDefaultFailureUrl("/login?error=locked"); setDefaultFailureUrl("/login?error=locked");
} else { } else {
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) { if (exception.getClass().isAssignableFrom(LockedException.class)) {
setDefaultFailureUrl("/login?error=badcredentials");
} else if (exception.getClass().isAssignableFrom(LockedException.class)) {
setDefaultFailureUrl("/login?error=locked"); setDefaultFailureUrl("/login?error=locked");
} }
} }
}
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
setDefaultFailureUrl("/login?error=badcredentials");
}
super.onAuthenticationFailure(request, response, exception); super.onAuthenticationFailure(request, response, exception);
} }
private boolean isDemoUser(String username) {
Optional<User> user = userService.findByUsername(username);
return user.isPresent()
&& user.get().getAuthorities().stream()
.anyMatch(authority -> "ROLE_DEMO_USER".equals(authority.getAuthority()));
}
} }

View File

@@ -9,6 +9,9 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@@ -18,6 +21,7 @@ import org.springframework.security.web.authentication.rememberme.PersistentToke
import org.springframework.security.web.savedrequest.NullRequestCache; import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.repository.JPATokenRepositoryImpl; import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
@Configuration @Configuration
@@ -44,6 +48,11 @@ public class SecurityConfiguration {
@Autowired private FirstLoginFilter firstLoginFilter; @Autowired private FirstLoginFilter firstLoginFilter;
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
@@ -53,6 +62,14 @@ public class SecurityConfiguration {
http.csrf(csrf -> csrf.disable()); http.csrf(csrf -> csrf.disable());
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class); http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
http.sessionManagement(
sessionManagement ->
sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(3)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry())
.expiredUrl("/login?logout=true"));
http.formLogin( http.formLogin(
formLogin -> formLogin ->
formLogin formLogin
@@ -62,7 +79,7 @@ public class SecurityConfiguration {
.defaultSuccessUrl("/") .defaultSuccessUrl("/")
.failureHandler( .failureHandler(
new CustomAuthenticationFailureHandler( new CustomAuthenticationFailureHandler(
loginAttemptService)) loginAttemptService, userService))
.permitAll()) .permitAll())
.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache())) .requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()))
.logout( .logout(
@@ -71,7 +88,19 @@ public class SecurityConfiguration {
new AntPathRequestMatcher("/logout")) new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout=true") .logoutSuccessUrl("/login?logout=true")
.invalidateHttpSession(true) // Invalidate session .invalidateHttpSession(true) // Invalidate session
.deleteCookies("JSESSIONID", "remember-me")) .deleteCookies("JSESSIONID", "remember-me")
.addLogoutHandler(
(request, response, authentication) -> {
HttpSession session =
request.getSession(
false);
if (session != null) {
String sessionId = session.getId();
sessionRegistry()
.removeSessionInformation(
sessionId);
}
}))
.rememberMe( .rememberMe(
rememberMeConfigurer -> rememberMeConfigurer ->
rememberMeConfigurer // Use the configurator directly rememberMeConfigurer // Use the configurator directly

View File

@@ -38,7 +38,7 @@ public class MergeController {
private static final Logger logger = LoggerFactory.getLogger(MergeController.class); private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
private PDDocument mergeDocuments(List<PDDocument> documents) throws IOException { public PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
PDDocument mergedDoc = new PDDocument(); PDDocument mergedDoc = new PDDocument();
for (PDDocument doc : documents) { for (PDDocument doc : documents) {
for (PDPage page : doc.getPages()) { for (PDPage page : doc.getPages()) {

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.awt.Color; import java.awt.Color;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -22,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -137,6 +137,7 @@ public class MultiPageLayoutController {
byte[] result = baos.toByteArray(); byte[] result = baos.toByteArray();
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
result, result,
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_layoutChanged.pdf"); Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
+ "_layoutChanged.pdf");
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -21,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -77,7 +77,8 @@ public class PdfOverlayController {
overlay.overlay(overlayGuide).save(outputStream); overlay.overlay(overlayGuide).save(outputStream);
byte[] data = outputStream.toByteArray(); byte[] data = outputStream.toByteArray();
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(baseFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(baseFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_overlayed.pdf"; // Remove file extension and append .pdf + "_overlayed.pdf"; // Remove file extension and append .pdf
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(

View File

@@ -1,8 +1,8 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -50,7 +51,9 @@ public class RearrangePagesPDFController {
String[] pageOrderArr = pagesToDelete.split(","); String[] pageOrderArr = pagesToDelete.split(",");
List<Integer> pagesToRemove = List<Integer> pagesToRemove =
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages()); GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), true);
Collections.sort(pagesToRemove);
for (int i = pagesToRemove.size() - 1; i >= 0; i--) { for (int i = pagesToRemove.size() - 1; i >= 0; i--) {
int pageIndex = pagesToRemove.get(i); int pageIndex = pagesToRemove.get(i);
@@ -58,7 +61,9 @@ public class RearrangePagesPDFController {
} }
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(pdfFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_removed_pages.pdf"); Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_removed_pages.pdf");
} }
private List<Integer> removeFirst(int totalPages) { private List<Integer> removeFirst(int totalPages) {
@@ -190,7 +195,7 @@ public class RearrangePagesPDFController {
if (sortType != null && sortType.length() > 0) { if (sortType != null && sortType.length() > 0) {
newPageOrder = processSortTypes(sortType, totalPages); newPageOrder = processSortTypes(sortType, totalPages);
} else { } else {
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages); newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, true);
} }
logger.info("newPageOrder = " + newPageOrder); logger.info("newPageOrder = " + newPageOrder);
logger.info("totalPages = " + totalPages); logger.info("totalPages = " + totalPages);
@@ -212,7 +217,8 @@ public class RearrangePagesPDFController {
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(pdfFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_rearranged.pdf"); + "_rearranged.pdf");
} catch (IOException e) { } catch (IOException e) {
logger.error("Failed rearranging documents", e); logger.error("Failed rearranging documents", e);

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
@@ -16,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -50,6 +50,8 @@ public class RotationController {
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(pdfFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_rotated.pdf"); Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_rotated.pdf");
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@@ -23,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -113,6 +113,7 @@ public class ScalePagesController {
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
baos.toByteArray(), baos.toByteArray(),
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_scaled.pdf"); Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
+ "_scaled.pdf");
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@@ -24,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -50,9 +50,13 @@ public class SplitPDFController {
PDDocument document = Loader.loadPDF(file.getBytes()); PDDocument document = Loader.loadPDF(file.getBytes());
List<Integer> pageNumbers = request.getPageNumbersList(document); List<Integer> pageNumbers = request.getPageNumbersList(document, true);
if (!pageNumbers.contains(document.getNumberOfPages() - 1)) if (!pageNumbers.contains(document.getNumberOfPages() - 1)) {
// Create a mutable ArrayList so we can add to it
pageNumbers = new ArrayList<>(pageNumbers);
pageNumbers.add(document.getNumberOfPages() - 1); pageNumbers.add(document.getNumberOfPages() - 1);
}
logger.info( logger.info(
"Splitting PDF into pages: {}", "Splitting PDF into pages: {}",
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(","))); pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
@@ -84,7 +88,9 @@ public class SplitPDFController {
Path zipFile = Files.createTempFile("split_documents", ".zip"); Path zipFile = Files.createTempFile("split_documents", ".zip");
String filename = Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", ""); String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) { try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
// loop through the split documents and write them to the zip file // loop through the split documents and write them to the zip file
for (int i = 0; i < splitDocumentsBoas.size(); i++) { for (int i = 0; i < splitDocumentsBoas.size(); i++) {

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@@ -27,6 +26,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -53,8 +53,21 @@ public class SplitPdfBySectionsController {
// Process the PDF based on split parameters // Process the PDF based on split parameters
int horiz = request.getHorizontalDivisions() + 1; int horiz = request.getHorizontalDivisions() + 1;
int verti = request.getVerticalDivisions() + 1; int verti = request.getVerticalDivisions() + 1;
boolean merge = request.isMerge();
List<PDDocument> splitDocuments = splitPdfPages(sourceDocument, verti, horiz); List<PDDocument> splitDocuments = splitPdfPages(sourceDocument, verti, horiz);
String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
if (merge) {
MergeController mergeController = new MergeController();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mergeController.mergeDocuments(splitDocuments).save(baos);
return WebResponseUtils.bytesToWebResponse(
baos.toByteArray(),
filename + "_split.pdf",
MediaType.APPLICATION_OCTET_STREAM);
}
for (PDDocument doc : splitDocuments) { for (PDDocument doc : splitDocuments) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.save(baos); doc.save(baos);
@@ -65,7 +78,6 @@ public class SplitPdfBySectionsController {
sourceDocument.close(); sourceDocument.close();
Path zipFile = Files.createTempFile("split_documents", ".zip"); Path zipFile = Files.createTempFile("split_documents", ".zip");
String filename = Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "");
byte[] data; byte[] data;
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) { try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api; package stirling.software.SPDF.controller.api;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@@ -21,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -121,7 +121,9 @@ public class SplitPdfBySizeController {
sourceDocument.close(); sourceDocument.close();
Path zipFile = Files.createTempFile("split_documents", ".zip"); Path zipFile = Files.createTempFile("split_documents", ".zip");
String filename = Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", ""); String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
byte[] data; byte[] data;
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) { try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {

View File

@@ -10,6 +10,9 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@@ -28,7 +31,6 @@ import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.Role; import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.api.user.UpdateUserDetails;
import stirling.software.SPDF.model.api.user.UsernameAndPass; import stirling.software.SPDF.model.api.user.UsernameAndPass;
@Controller @Controller
@@ -50,53 +52,6 @@ public class UserController {
return "redirect:/login?registered=true"; return "redirect:/login?registered=true";
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-username-and-password")
public RedirectView changeUsernameAndPassword(
Principal principal,
@ModelAttribute UpdateUserDetails requestModel,
HttpServletRequest request,
HttpServletResponse response,
RedirectAttributes redirectAttributes) {
String currentPassword = requestModel.getPassword();
String newPassword = requestModel.getNewPassword();
String newUsername = requestModel.getNewUsername();
if (principal == null) {
return new RedirectView("/change-creds?messageType=notAuthenticated");
}
Optional<User> userOpt = userService.findByUsername(principal.getName());
if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/change-creds?messageType=userNotFound");
}
User user = userOpt.get();
if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/change-creds?messageType=incorrectPassword");
}
if (!user.getUsername().equals(newUsername) && userService.usernameExists(newUsername)) {
return new RedirectView("/change-creds?messageType=usernameExists");
}
userService.changePassword(user, newPassword);
if (newUsername != null
&& newUsername.length() > 0
&& !user.getUsername().equals(newUsername)) {
userService.changeUsername(user, newUsername);
}
userService.changeFirstUse(user, false);
// Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null);
return new RedirectView("/login?messageType=credsUpdated");
}
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-username") @PostMapping("/change-username")
public RedirectView changeUsername( public RedirectView changeUsername(
@@ -136,6 +91,39 @@ public class UserController {
return new RedirectView("/login?messageType=credsUpdated"); return new RedirectView("/login?messageType=credsUpdated");
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-password-on-login")
public RedirectView changePasswordOnLogin(
Principal principal,
@RequestParam String currentPassword,
@RequestParam String newPassword,
HttpServletRequest request,
HttpServletResponse response,
RedirectAttributes redirectAttributes) {
if (principal == null) {
return new RedirectView("/change-creds?messageType=notAuthenticated");
}
Optional<User> userOpt = userService.findByUsername(principal.getName());
if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/change-creds?messageType=userNotFound");
}
User user = userOpt.get();
if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/change-creds?messageType=incorrectPassword");
}
userService.changePassword(user, newPassword);
userService.changeFirstUse(user, false);
// Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null);
return new RedirectView("/login?messageType=credsUpdated");
}
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-password") @PostMapping("/change-password")
public RedirectView changePassword( public RedirectView changePassword(
@@ -219,18 +207,38 @@ public class UserController {
@PreAuthorize("hasRole('ROLE_ADMIN')") @PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/admin/deleteUser/{username}") @PostMapping("/admin/deleteUser/{username}")
public String deleteUser(@PathVariable String username, Authentication authentication) { public RedirectView deleteUser(@PathVariable String username, Authentication authentication) {
if (!userService.usernameExists(username)) {
return new RedirectView("/addUsers?messageType=deleteUsernameExists");
}
// Get the currently authenticated username // Get the currently authenticated username
String currentUsername = authentication.getName(); String currentUsername = authentication.getName();
// Check if the provided username matches the current session's username // Check if the provided username matches the current session's username
if (currentUsername.equals(username)) { if (currentUsername.equals(username)) {
throw new IllegalArgumentException("Cannot delete currently logined in user."); return new RedirectView("/addUsers?messageType=deleteCurrentUser");
}
invalidateUserSessions(username);
userService.deleteUser(username);
return new RedirectView("/addUsers");
} }
userService.deleteUser(username); @Autowired private SessionRegistry sessionRegistry;
return "redirect:/addUsers";
private void invalidateUserSessions(String username) {
for (Object principal : sessionRegistry.getAllPrincipals()) {
if (principal instanceof UserDetails) {
UserDetails userDetails = (UserDetails) principal;
if (userDetails.getUsername().equals(username)) {
for (SessionInformation session :
sessionRegistry.getAllSessions(principal, false)) {
session.expireNow();
}
}
}
}
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import io.github.pixee.security.Filenames;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -10,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -23,21 +23,21 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class ConvertBookToPDFController { public class ConvertBookToPDFController {
@Autowired @Autowired
@Qualifier("bookFormatsInstalled") @Qualifier("bookAndHtmlFormatsInstalled")
private boolean bookFormatsInstalled; private boolean bookAndHtmlFormatsInstalled;
@PostMapping(consumes = "multipart/form-data", value = "/book/pdf") @PostMapping(consumes = "multipart/form-data", value = "/book/pdf")
@Operation( @Operation(
summary = summary =
"Convert a BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) to PDF", "Convert a BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) to PDF",
description = description =
"(Requires bookFormatsInstalled flag and Calibre installed) This endpoint takes an BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) input and converts it to PDF format.") "(Requires bookAndHtmlFormatsInstalled flag and Calibre installed) This endpoint takes an BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) input and converts it to PDF format.")
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute GeneralFile request) throws Exception { public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute GeneralFile request) throws Exception {
MultipartFile fileInput = request.getFileInput(); MultipartFile fileInput = request.getFileInput();
if (!bookFormatsInstalled) { if (!bookAndHtmlFormatsInstalled) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"bookFormatsInstalled flag is False, this functionality is not avaiable"); "bookAndHtmlFormatsInstalled flag is False, this functionality is not avaiable");
} }
if (fileInput == null) { if (fileInput == null) {

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import io.github.pixee.security.Filenames;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -10,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -23,8 +23,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class ConvertHtmlToPDF { public class ConvertHtmlToPDF {
@Autowired @Autowired
@Qualifier("htmlFormatsInstalled") @Qualifier("bookAndHtmlFormatsInstalled")
private boolean htmlFormatsInstalled; private boolean bookAndHtmlFormatsInstalled;
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf") @PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@Operation( @Operation(
@@ -47,7 +47,10 @@ public class ConvertHtmlToPDF {
} }
byte[] pdfBytes = byte[] pdfBytes =
FileToPdf.convertHtmlToPdf( FileToPdf.convertHtmlToPdf(
request, fileInput.getBytes(), originalFilename, htmlFormatsInstalled); request,
fileInput.getBytes(),
originalFilename,
bookAndHtmlFormatsInstalled);
String outputFilename = String outputFilename =
originalFilename.replaceFirst("[.][^.]+$", "") originalFilename.replaceFirst("[.][^.]+$", "")

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import java.net.URLConnection; import java.net.URLConnection;
@@ -19,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -57,7 +57,9 @@ public class ConvertImgPDFController {
// returns bytes for image // returns bytes for image
boolean singleImage = "single".equals(singleOrMultiple); boolean singleImage = "single".equals(singleOrMultiple);
byte[] result = null; byte[] result = null;
String filename = Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", ""); String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
try { try {
result = result =
PdfUtils.convertFromPdf( PdfUtils.convertFromPdf(

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import io.github.pixee.security.Filenames;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -20,6 +19,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -33,8 +33,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class ConvertMarkdownToPdf { public class ConvertMarkdownToPdf {
@Autowired @Autowired
@Qualifier("htmlFormatsInstalled") @Qualifier("bookAndHtmlFormatsInstalled")
private boolean htmlFormatsInstalled; private boolean bookAndHtmlFormatsInstalled;
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf") @PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@Operation( @Operation(
@@ -69,7 +69,10 @@ public class ConvertMarkdownToPdf {
byte[] pdfBytes = byte[] pdfBytes =
FileToPdf.convertHtmlToPdf( FileToPdf.convertHtmlToPdf(
null, htmlContent.getBytes(), "converted.html", htmlFormatsInstalled); null,
htmlContent.getBytes(),
"converted.html",
bookAndHtmlFormatsInstalled);
String outputFilename = String outputFilename =
originalFilename.replaceFirst("[.][^.]+$", "") originalFilename.replaceFirst("[.][^.]+$", "")

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -90,7 +90,8 @@ public class ConvertOfficeController {
byte[] pdfByteArray = convertToPdf(inputFile); byte[] pdfByteArray = convertToPdf(inputFile);
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
pdfByteArray, pdfByteArray,
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_convertedToPDF.pdf"); + "_convertedToPDF.pdf");
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import io.github.pixee.security.Filenames;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@@ -16,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -30,22 +30,22 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class ConvertPDFToBookController { public class ConvertPDFToBookController {
@Autowired @Autowired
@Qualifier("bookFormatsInstalled") @Qualifier("bookAndHtmlFormatsInstalled")
private boolean bookFormatsInstalled; private boolean bookAndHtmlFormatsInstalled;
@PostMapping(consumes = "multipart/form-data", value = "/pdf/book") @PostMapping(consumes = "multipart/form-data", value = "/pdf/book")
@Operation( @Operation(
summary = summary =
"Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF", "Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF",
description = description =
"(Requires bookFormatsInstalled flag and Calibre installed) This endpoint Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF") "(Requires bookAndHtmlFormatsInstalled flag and Calibre installed) This endpoint Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF")
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute PdfToBookRequest request) public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute PdfToBookRequest request)
throws Exception { throws Exception {
MultipartFile fileInput = request.getFileInput(); MultipartFile fileInput = request.getFileInput();
if (!bookFormatsInstalled) { if (!bookAndHtmlFormatsInstalled) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"bookFormatsInstalled flag is False, this functionality is not avaiable"); "bookAndHtmlFormatsInstalled flag is False, this functionality is not avaiable");
} }
if (fileInput == null) { if (fileInput == null) {
@@ -93,7 +93,8 @@ public class ConvertPDFToBookController {
} }
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(fileInput.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(fileInput.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "." + "."
+ outputFormat; // Remove file extension and append .pdf + outputFormat; // Remove file extension and append .pdf

View File

@@ -2,6 +2,10 @@ package stirling.software.SPDF.controller.api.converters;
import java.io.IOException; import java.io.IOException;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -9,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -17,6 +22,7 @@ import stirling.software.SPDF.model.api.converters.PdfToPresentationRequest;
import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest; import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest;
import stirling.software.SPDF.model.api.converters.PdfToWordRequest; import stirling.software.SPDF.model.api.converters.PdfToWordRequest;
import stirling.software.SPDF.utils.PDFToFile; import stirling.software.SPDF.utils.PDFToFile;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController @RestController
@RequestMapping("/api/v1/convert") @RequestMapping("/api/v1/convert")
@@ -59,10 +65,22 @@ public class ConvertPDFToOffice {
throws IOException, InterruptedException { throws IOException, InterruptedException {
MultipartFile inputFile = request.getFileInput(); MultipartFile inputFile = request.getFileInput();
String outputFormat = request.getOutputFormat(); String outputFormat = request.getOutputFormat();
if ("txt".equals(request.getOutputFormat())) {
try (PDDocument document = Loader.loadPDF(inputFile.getBytes())) {
PDFTextStripper stripper = new PDFTextStripper();
String text = stripper.getText(document);
return WebResponseUtils.bytesToWebResponse(
text.getBytes(),
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ ".txt",
MediaType.TEXT_PLAIN);
}
} else {
PDFToFile pdfToFile = new PDFToFile(); PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import"); return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
} }
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf/word") @PostMapping(consumes = "multipart/form-data", value = "/pdf/word")
@Operation( @Operation(

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import io.github.pixee.security.Filenames;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@@ -13,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -64,7 +64,9 @@ public class ConvertPDFToPDFA {
// Return the optimized PDF as a response // Return the optimized PDF as a response
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_PDFA.pdf"; Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_PDFA.pdf";
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
} }
} }

View File

@@ -29,8 +29,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class ConvertWebsiteToPDF { public class ConvertWebsiteToPDF {
@Autowired @Autowired
@Qualifier("htmlFormatsInstalled") @Qualifier("bookAndHtmlFormatsInstalled")
private boolean htmlFormatsInstalled; private boolean bookAndHtmlFormatsInstalled;
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf") @PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@Operation( @Operation(
@@ -53,7 +53,7 @@ public class ConvertWebsiteToPDF {
// Prepare the OCRmyPDF command // Prepare the OCRmyPDF command
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
if (!htmlFormatsInstalled) { if (!bookAndHtmlFormatsInstalled) {
command.add("weasyprint"); command.add("weasyprint");
} else { } else {
command.add("wkhtmltopdf"); command.add("wkhtmltopdf");

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.filters; package stirling.software.SPDF.controller.api.filters;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
@@ -14,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
@@ -19,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -134,7 +134,8 @@ public class AutoRenameController {
return WebResponseUtils.pdfDocToWebResponse(document, header + ".pdf"); return WebResponseUtils.pdfDocToWebResponse(document, header + ".pdf");
} else { } else {
logger.info("File has no good title to be found"); logger.info("File has no good title to be found");
return WebResponseUtils.pdfDocToWebResponse(document, Filenames.toSimpleFileName(file.getOriginalFilename())); return WebResponseUtils.pdfDocToWebResponse(
document, Filenames.toSimpleFileName(file.getOriginalFilename()));
} }
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte; import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt; import java.awt.image.DataBufferInt;
@@ -32,6 +31,7 @@ import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer; import com.google.zxing.common.HybridBinarizer;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -98,7 +98,9 @@ public class AutoSplitPdfController {
document.close(); document.close();
Path zipFile = Files.createTempFile("split_documents", ".zip"); Path zipFile = Files.createTempFile("split_documents", ".zip");
String filename = Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", ""); String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
byte[] data; byte[] data;
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) { try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {

View File

@@ -1,25 +1,21 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import javax.imageio.ImageIO;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageTree; import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.text.PDFTextStripper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@@ -28,12 +24,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest; import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;
@RestController @RestController
@@ -41,6 +37,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
public class BlankPageController { public class BlankPageController {
private static final Logger logger = LoggerFactory.getLogger(BlankPageController.class);
@PostMapping(consumes = "multipart/form-data", value = "/remove-blanks") @PostMapping(consumes = "multipart/form-data", value = "/remove-blanks")
@Operation( @Operation(
summary = "Remove blank pages from a PDF file", summary = "Remove blank pages from a PDF file",
@@ -63,63 +61,35 @@ public class BlankPageController {
PDFRenderer pdfRenderer = new PDFRenderer(document); PDFRenderer pdfRenderer = new PDFRenderer(document);
for (PDPage page : pages) { for (PDPage page : pages) {
System.out.println("checking page " + pageIndex); logger.info("checking page " + pageIndex);
textStripper.setStartPage(pageIndex + 1); textStripper.setStartPage(pageIndex + 1);
textStripper.setEndPage(pageIndex + 1); textStripper.setEndPage(pageIndex + 1);
String pageText = textStripper.getText(document); String pageText = textStripper.getText(document);
boolean hasText = !pageText.trim().isEmpty(); boolean hasText = !pageText.trim().isEmpty();
Boolean blank = false;
if (hasText) { if (hasText) {
pagesToKeepIndex.add(pageIndex); logger.info("page " + pageIndex + " has text, not blank");
System.out.println("page " + pageIndex + " has text"); blank = false;
} else { } else {
boolean hasImages = PdfUtils.hasImagesOnPage(page); boolean hasImages = PdfUtils.hasImagesOnPage(page);
if (hasImages) { if (hasImages) {
System.out.println("page " + pageIndex + " has image"); logger.info("page " + pageIndex + " has image, running blank detection");
Path tempFile = Files.createTempFile("image_", ".png");
// Render image and save as temp file // Render image and save as temp file
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 300); BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 30);
ImageIO.write(image, "png", tempFile.toFile()); blank = isBlankImage(image, threshold, whitePercent, threshold);
}
List<String> command =
new ArrayList<>(
Arrays.asList(
"python",
System.getProperty("user.dir")
+ "/scripts/detect-blank-pages.py",
tempFile.toString(),
"--threshold",
String.valueOf(threshold),
"--white_percent",
String.valueOf(whitePercent)));
Boolean blank = false;
// Run CLI command
try {
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
.runCommandWithOutputHandling(command);
} catch (IOException e) {
// From detect-blank-pages.py
// Return code 1: The image is considered blank.
// Return code 0: The image is not considered blank.
// Since the process returned with a failure code, it should be blank.
blank = true;
} }
if (blank) { if (blank) {
System.out.println("Skipping, Image was blank for page #" + pageIndex); logger.info("Skipping, Image was blank for page #" + pageIndex);
} else { } else {
System.out.println( logger.info("page " + pageIndex + " has image which is not blank");
"page " + pageIndex + " has image which is not blank");
pagesToKeepIndex.add(pageIndex); pagesToKeepIndex.add(pageIndex);
} }
}
}
pageIndex++; pageIndex++;
} }
System.out.print("pagesToKeep=" + pagesToKeepIndex.size());
// Remove pages not present in pagesToKeepIndex // Remove pages not present in pagesToKeepIndex
List<Integer> pageIndices = List<Integer> pageIndices =
IntStream.range(0, pages.getCount()).boxed().collect(Collectors.toList()); IntStream.range(0, pages.getCount()).boxed().collect(Collectors.toList());
@@ -132,7 +102,8 @@ public class BlankPageController {
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_blanksRemoved.pdf"); + "_blanksRemoved.pdf");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@@ -141,4 +112,30 @@ public class BlankPageController {
if (document != null) document.close(); if (document != null) document.close();
} }
} }
public static boolean isBlankImage(
BufferedImage image, int threshold, double whitePercent, int blurSize) {
if (image == null) {
logger.info("Error: Image is null");
return false;
}
// Convert to binary image based on the threshold
int whitePixels = 0;
int totalPixels = image.getWidth() * image.getHeight();
for (int i = 0; i < image.getHeight(); i++) {
for (int j = 0; j < image.getWidth(); j++) {
int color = image.getRGB(j, i) & 0xFF;
if (color >= 255 - threshold) {
whitePixels++;
}
}
}
double whitePixelPercentage = (whitePixels / (double) totalPixels) * 100;
logger.info(String.format("Page has white pixel percent of %.2f%%", whitePixelPercentage));
return whitePixelPercentage >= whitePercent;
}
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.awt.Image; import java.awt.Image;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@@ -30,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -265,7 +265,9 @@ public class CompressController {
// Return the optimized PDF as a response // Return the optimized PDF as a response
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_Optimized.pdf"; Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_Optimized.pdf";
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
} }
} }

View File

@@ -73,6 +73,12 @@ public class ExtractImageScansController {
List<String> images = new ArrayList<>(); List<String> images = new ArrayList<>();
List<Path> tempImageFiles = new ArrayList<>();
Path tempInputFile = null;
Path tempZipFile = null;
List<Path> tempDirs = new ArrayList<>();
try {
// Check if input file is a PDF // Check if input file is a PDF
if ("pdf".equalsIgnoreCase(extension)) { if ("pdf".equalsIgnoreCase(extension)) {
// Load PDF document // Load PDF document
@@ -92,10 +98,11 @@ public class ExtractImageScansController {
// Add temp file path to images list // Add temp file path to images list
images.add(tempFile.toString()); images.add(tempFile.toString());
tempImageFiles.add(tempFile);
} }
} }
} else { } else {
Path tempInputFile = Files.createTempFile("input_", "." + extension); tempInputFile = Files.createTempFile("input_", "." + extension);
Files.copy( Files.copy(
form.getFileInput().getInputStream(), form.getFileInput().getInputStream(),
tempInputFile, tempInputFile,
@@ -110,6 +117,7 @@ public class ExtractImageScansController {
for (int i = 0; i < images.size(); i++) { for (int i = 0; i < images.size(); i++) {
Path tempDir = Files.createTempDirectory("openCV_output"); Path tempDir = Files.createTempDirectory("openCV_output");
tempDirs.add(tempDir);
List<String> command = List<String> command =
new ArrayList<>( new ArrayList<>(
Arrays.asList( Arrays.asList(
@@ -146,7 +154,7 @@ public class ExtractImageScansController {
// Create zip file if multiple images // Create zip file if multiple images
if (processedImageBytes.size() > 1) { if (processedImageBytes.size() > 1) {
String outputZipFilename = fileName.replaceFirst("[.][^.]+$", "") + "_processed.zip"; String outputZipFilename = fileName.replaceFirst("[.][^.]+$", "") + "_processed.zip";
Path tempZipFile = Files.createTempFile("output_", ".zip"); tempZipFile = Files.createTempFile("output_", ".zip");
try (ZipOutputStream zipOut = try (ZipOutputStream zipOut =
new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) { new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) {
@@ -179,5 +187,31 @@ public class ExtractImageScansController {
fileName.replaceFirst("[.][^.]+$", "") + ".png", fileName.replaceFirst("[.][^.]+$", "") + ".png",
MediaType.IMAGE_PNG); MediaType.IMAGE_PNG);
} }
} finally {
// Cleanup logic for all temporary files and directories
tempImageFiles.forEach(path -> {
try {
Files.deleteIfExists(path);
} catch (IOException e) {
logger.error("Failed to delete temporary image file: " + path, e);
}
});
if (tempZipFile != null && Files.exists(tempZipFile)) {
try {
Files.delete(tempZipFile);
} catch (IOException e) {
logger.error("Failed to delete temporary zip file: " + tempZipFile, e);
}
}
tempDirs.forEach(dir -> {
try {
FileUtils.deleteDirectory(dir.toFile());
} catch (IOException e) {
logger.error("Failed to delete temporary directory: " + dir, e);
}
});
}
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Image; import java.awt.Image;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@@ -30,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -67,7 +67,9 @@ public class ExtractImagesController {
zos.setLevel(Deflater.BEST_COMPRESSION); zos.setLevel(Deflater.BEST_COMPRESSION);
int imageIndex = 1; int imageIndex = 1;
String filename = Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", ""); String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
int pageNum = 0; int pageNum = 0;
Set<Integer> processedImages = new HashSet<>(); Set<Integer> processedImages = new HashSet<>();
// Iterate over each page // Iterate over each page

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.awt.Color; import java.awt.Color;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp; import java.awt.image.AffineTransformOp;
@@ -34,6 +33,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -142,7 +142,9 @@ public class FakeScanControllerWIP {
// Return the optimized PDF as a response // Return the optimized PDF as a response
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_scanned.pdf"; Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_scanned.pdf";
return WebResponseUtils.boasToWebResponse(baos, outputFilename); return WebResponseUtils.boasToWebResponse(baos, outputFilename);
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -19,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -165,6 +165,8 @@ public class MetadataController {
document.setDocumentInformation(info); document.setDocumentInformation(info);
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(pdfFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_metadata.pdf"); Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_metadata.pdf");
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -25,6 +24,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -41,7 +41,7 @@ public class OCRController {
private static final Logger logger = LoggerFactory.getLogger(OCRController.class); private static final Logger logger = LoggerFactory.getLogger(OCRController.class);
public List<String> getAvailableTesseractLanguages() { public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tesseract-ocr/5/tessdata"; String tessdataDir = "/usr/share/tessdata";
File[] files = new File(tessdataDir).listFiles(); File[] files = new File(tessdataDir).listFiles();
if (files == null) { if (files == null) {
return Collections.emptyList(); return Collections.emptyList();
@@ -183,12 +183,16 @@ public class OCRController {
// Return the OCR processed PDF as a response // Return the OCR processed PDF as a response
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_OCR.pdf"; Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_OCR.pdf";
if (sidecar != null && sidecar) { if (sidecar != null && sidecar) {
// Create a zip file containing both the PDF and the text file // Create a zip file containing both the PDF and the text file
String outputZipFilename = String outputZipFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_OCR.zip"; Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_OCR.zip";
Path tempZipFile = Files.createTempFile("output_", ".zip"); Path tempZipFile = Files.createTempFile("output_", ".zip");
try (ZipOutputStream zipOut = try (ZipOutputStream zipOut =

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -13,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -45,7 +45,9 @@ public class OverlayImageController {
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
result, result,
Filenames.toSimpleFileName(pdfFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_overlayed.pdf"); Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_overlayed.pdf");
} catch (IOException e) { } catch (IOException e) {
logger.error("Failed to add image to PDF", e); logger.error("Failed to add image to PDF", e);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(HttpStatus.BAD_REQUEST);

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -22,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -146,7 +146,8 @@ public class PageNumbersController {
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
baos.toByteArray(), baos.toByteArray(),
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_numbersAdded.pdf", Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
+ "_numbersAdded.pdf",
MediaType.APPLICATION_PDF); MediaType.APPLICATION_PDF);
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -16,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -66,7 +66,9 @@ public class RepairController {
// Return the optimized PDF as a response // Return the optimized PDF as a response
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_repaired.pdf"; Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_repaired.pdf";
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map; import java.util.Map;
@@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -55,7 +55,8 @@ public class ShowJavascript {
script += script +=
"// File: " "// File: "
+ Filenames.toSimpleFileName(inputFile.getOriginalFilename()) + Filenames.toSimpleFileName(
inputFile.getOriginalFilename())
+ ", Script: " + ", Script: "
+ name + name
+ "\n" + "\n"
@@ -67,12 +68,14 @@ public class ShowJavascript {
if (script.isEmpty()) { if (script.isEmpty()) {
script = script =
"PDF '" + inputFile.getOriginalFilename() + "' does not contain Javascript"; "PDF '"
+ Filenames.toSimpleFileName(inputFile.getOriginalFilename())
+ "' does not contain Javascript";
} }
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
script.getBytes(StandardCharsets.UTF_8), script.getBytes(StandardCharsets.UTF_8),
inputFile.getOriginalFilename() + ".js"); Filenames.toSimpleFileName(inputFile.getOriginalFilename()) + ".js");
} }
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.Filenames;
import java.awt.Color; import java.awt.Color;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
@@ -8,6 +7,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.List;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@@ -33,6 +33,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -48,13 +49,13 @@ public class StampController {
@Operation( @Operation(
summary = "Add stamp to a PDF file", summary = "Add stamp to a PDF file",
description = description =
"This endpoint adds a stamp to a given PDF file. Users can specify the watermark type (text or image), rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO") "This endpoint adds a stamp to a given PDF file. Users can specify the stamp type (text or image), rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request) public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
throws IOException, Exception { throws IOException, Exception {
MultipartFile pdfFile = request.getFileInput(); MultipartFile pdfFile = request.getFileInput();
String watermarkType = request.getStampType(); String stampType = request.getStampType();
String watermarkText = request.getStampText(); String stampText = request.getStampText();
MultipartFile watermarkImage = request.getStampImage(); MultipartFile stampImage = request.getStampImage();
String alphabet = request.getAlphabet(); String alphabet = request.getAlphabet();
float fontSize = request.getFontSize(); float fontSize = request.getFontSize();
float rotation = request.getRotation(); float rotation = request.getRotation();
@@ -65,6 +66,7 @@ public class StampController {
String customColor = request.getCustomColor(); String customColor = request.getCustomColor();
float marginFactor; float marginFactor;
switch (request.getCustomMargin().toLowerCase()) { switch (request.getCustomMargin().toLowerCase()) {
case "small": case "small":
marginFactor = 0.02f; marginFactor = 0.02f;
@@ -78,7 +80,6 @@ public class StampController {
case "x-large": case "x-large":
marginFactor = 0.075f; marginFactor = 0.075f;
break; break;
default: default:
marginFactor = 0.035f; marginFactor = 0.035f;
break; break;
@@ -87,7 +88,15 @@ public class StampController {
// Load the input PDF // Load the input PDF
PDDocument document = Loader.loadPDF(pdfFile.getBytes()); PDDocument document = Loader.loadPDF(pdfFile.getBytes());
for (PDPage page : document.getPages()) { List<Integer> pageNumbers = request.getPageNumbersList(document, false);
for (int pageIndex : pageNumbers) {
int zeroBasedIndex = pageIndex - 1;
if (zeroBasedIndex >= 0 && zeroBasedIndex < document.getNumberOfPages()) {
PDPage page = document.getPage(zeroBasedIndex);
PDRectangle pageSize = page.getMediaBox();
float margin = marginFactor * (pageSize.getWidth() + pageSize.getHeight()) / 2;
PDPageContentStream contentStream = PDPageContentStream contentStream =
new PDPageContentStream( new PDPageContentStream(
document, page, PDPageContentStream.AppendMode.APPEND, true, true); document, page, PDPageContentStream.AppendMode.APPEND, true, true);
@@ -96,10 +105,10 @@ public class StampController {
graphicsState.setNonStrokingAlphaConstant(opacity); graphicsState.setNonStrokingAlphaConstant(opacity);
contentStream.setGraphicsStateParameters(graphicsState); contentStream.setGraphicsStateParameters(graphicsState);
if ("text".equalsIgnoreCase(watermarkType)) { if ("text".equalsIgnoreCase(stampType)) {
addTextStamp( addTextStamp(
contentStream, contentStream,
watermarkText, stampText,
document, document,
page, page,
rotation, rotation,
@@ -108,12 +117,12 @@ public class StampController {
alphabet, alphabet,
overrideX, overrideX,
overrideY, overrideY,
marginFactor, margin,
customColor); customColor);
} else if ("image".equalsIgnoreCase(watermarkType)) { } else if ("image".equalsIgnoreCase(stampType)) {
addImageStamp( addImageStamp(
contentStream, contentStream,
watermarkImage, stampImage,
document, document,
page, page,
rotation, rotation,
@@ -121,20 +130,22 @@ public class StampController {
fontSize, fontSize,
overrideX, overrideX,
overrideY, overrideY,
marginFactor); margin);
} }
contentStream.close(); contentStream.close();
} }
}
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(pdfFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_watermarked.pdf"); Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_stamped.pdf");
} }
private void addTextStamp( private void addTextStamp(
PDPageContentStream contentStream, PDPageContentStream contentStream,
String watermarkText, String stampText,
PDDocument document, PDDocument document,
PDPage page, PDPage page,
float rotation, float rotation,
@@ -143,7 +154,7 @@ public class StampController {
String alphabet, String alphabet,
float overrideX, // X override float overrideX, // X override
float overrideY, float overrideY,
float marginFactor, float margin,
String colorString) // Y override String colorString) // Y override
throws IOException { throws IOException {
String resourceDir = ""; String resourceDir = "";
@@ -203,27 +214,21 @@ public class StampController {
x = overrideX; x = overrideX;
y = overrideY; y = overrideY;
} else { } else {
x = x = calculatePositionX(pageSize, position, fontSize, font, fontSize, stampText, margin);
calculatePositionX( y =
pageSize, calculatePositionY(
position, pageSize, position, calculateTextCapHeight(font, fontSize), margin);
fontSize,
font,
fontSize,
watermarkText,
marginFactor);
y = calculatePositionY(pageSize, position, fontSize, marginFactor);
} }
contentStream.beginText(); contentStream.beginText();
contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(rotation), x, y)); contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(rotation), x, y));
contentStream.showText(watermarkText); contentStream.showText(stampText);
contentStream.endText(); contentStream.endText();
} }
private void addImageStamp( private void addImageStamp(
PDPageContentStream contentStream, PDPageContentStream contentStream,
MultipartFile watermarkImage, MultipartFile stampImage,
PDDocument document, PDDocument document,
PDPage page, PDPage page,
float rotation, float rotation,
@@ -231,11 +236,11 @@ public class StampController {
float fontSize, float fontSize,
float overrideX, float overrideX,
float overrideY, float overrideY,
float marginFactor) float margin)
throws IOException { throws IOException {
// Load the watermark image // Load the stamp image
BufferedImage image = ImageIO.read(watermarkImage.getInputStream()); BufferedImage image = ImageIO.read(stampImage.getInputStream());
// Compute width based on original aspect ratio // Compute width based on original aspect ratio
float aspectRatio = (float) image.getWidth() / (float) image.getHeight(); float aspectRatio = (float) image.getWidth() / (float) image.getHeight();
@@ -257,10 +262,8 @@ public class StampController {
x = overrideX; x = overrideX;
y = overrideY; y = overrideY;
} else { } else {
x = x = calculatePositionX(pageSize, position, desiredPhysicalWidth, null, 0, null, margin);
calculatePositionX( y = calculatePositionY(pageSize, position, fontSize, margin);
pageSize, position, desiredPhysicalWidth, null, 0, null, marginFactor);
y = calculatePositionY(pageSize, position, fontSize, marginFactor);
} }
contentStream.saveGraphicsState(); contentStream.saveGraphicsState();
@@ -277,17 +280,31 @@ public class StampController {
PDFont font, PDFont font,
float fontSize, float fontSize,
String text, String text,
float marginFactor) float margin)
throws IOException { throws IOException {
float actualWidth = float actualWidth =
(text != null) ? calculateTextWidth(text, font, fontSize) : contentWidth; (text != null) ? calculateTextWidth(text, font, fontSize) : contentWidth;
switch (position % 3) { switch (position % 3) {
case 1: // Left case 1: // Left
return pageSize.getLowerLeftX() + marginFactor * pageSize.getWidth(); return pageSize.getLowerLeftX() + margin;
case 2: // Center case 2: // Center
return (pageSize.getWidth() - actualWidth) / 2; return (pageSize.getWidth() - actualWidth) / 2;
case 0: // Right case 0: // Right
return pageSize.getUpperRightX() - actualWidth - marginFactor * pageSize.getWidth(); return pageSize.getUpperRightX() - actualWidth - margin;
default:
return 0;
}
}
private float calculatePositionY(
PDRectangle pageSize, int position, float height, float margin) {
switch ((position - 1) / 3) {
case 0: // Top
return pageSize.getUpperRightY() - height - margin;
case 1: // Middle
return (pageSize.getHeight() - height) / 2;
case 2: // Bottom
return pageSize.getLowerLeftY() + margin;
default: default:
return 0; return 0;
} }
@@ -297,17 +314,7 @@ public class StampController {
return font.getStringWidth(text) / 1000 * fontSize; return font.getStringWidth(text) / 1000 * fontSize;
} }
private float calculatePositionY( private float calculateTextCapHeight(PDFont font, float fontSize) {
PDRectangle pageSize, int position, float height, float marginFactor) { return font.getFontDescriptor().getCapHeight() / 1000 * fontSize;
switch ((position - 1) / 3) {
case 0: // Top
return pageSize.getUpperRightY() - height - marginFactor * pageSize.getHeight();
case 1: // Middle
return (pageSize.getHeight() - height) / 2;
case 2: // Bottom
return pageSize.getLowerLeftY() + marginFactor * pageSize.getHeight();
default:
return 0;
}
} }
} }

View File

@@ -36,7 +36,7 @@ public class ApiDocService {
private String getApiDocsUrl() { private String getApiDocsUrl() {
String contextPath = servletContext.getContextPath(); String contextPath = servletContext.getContextPath();
String port = SPdfApplication.getPort(); String port = SPdfApplication.getStaticPort();
return "http://localhost:" + port + contextPath + "/v1/api-docs"; return "http://localhost:" + port + contextPath + "/v1/api-docs";
} }

View File

@@ -1,7 +1,5 @@
package stirling.software.SPDF.controller.api.pipeline; package stirling.software.SPDF.controller.api.pipeline;
import io.github.pixee.security.Filenames;
import io.github.pixee.security.ZipSecurity;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@@ -38,6 +36,9 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.github.pixee.security.ZipSecurity;
import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContext;
import stirling.software.SPDF.SPdfApplication; import stirling.software.SPDF.SPdfApplication;
import stirling.software.SPDF.model.PipelineConfig; import stirling.software.SPDF.model.PipelineConfig;
@@ -63,7 +64,7 @@ public class PipelineProcessor {
private String getBaseUrl() { private String getBaseUrl() {
String contextPath = servletContext.getContextPath(); String contextPath = servletContext.getContextPath();
String port = SPdfApplication.getPort(); String port = SPdfApplication.getStaticPort();
return "http://localhost:" + port + contextPath + "/"; return "http://localhost:" + port + contextPath + "/";
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.security; package stirling.software.SPDF.controller.api.security;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -43,6 +42,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -124,7 +124,9 @@ public class CertSignController {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
sign(pdf.getBytes(), baos, createSignature, name, location, reason); sign(pdf.getBytes(), baos, createSignature, name, location, reason);
return WebResponseUtils.boasToWebResponse( return WebResponseUtils.boasToWebResponse(
baos, Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_signed.pdf"); baos,
Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
+ "_signed.pdf");
} }
private static void sign( private static void sign(

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.security; package stirling.software.SPDF.controller.api.security;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
@@ -16,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -44,7 +44,8 @@ public class PasswordController {
document.setAllSecurityToBeRemoved(true); document.setAllSecurityToBeRemoved(true);
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(fileInput.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(fileInput.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_password_removed.pdf"); + "_password_removed.pdf");
} }
@@ -89,10 +90,13 @@ public class PasswordController {
if ("".equals(ownerPassword) && "".equals(password)) if ("".equals(ownerPassword) && "".equals(password))
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(fileInput.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(fileInput.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_permissions.pdf"); + "_permissions.pdf");
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(fileInput.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_passworded.pdf"); Filenames.toSimpleFileName(fileInput.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_passworded.pdf");
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.security; package stirling.software.SPDF.controller.api.security;
import io.github.pixee.security.Filenames;
import java.awt.Color; import java.awt.Color;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -26,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -105,7 +105,8 @@ public class RedactController {
byte[] pdfContent = baos.toByteArray(); byte[] pdfContent = baos.toByteArray();
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
pdfContent, pdfContent,
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_redacted.pdf"); Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
+ "_redacted.pdf");
} }
private void redactFoundText( private void redactFoundText(

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.security; package stirling.software.SPDF.controller.api.security;
import io.github.pixee.security.Filenames;
import java.io.IOException; import java.io.IOException;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
@@ -29,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -77,7 +77,8 @@ public class SanitizeController {
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_sanitized.pdf"); + "_sanitized.pdf");
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.api.security; package stirling.software.SPDF.controller.api.security;
import io.github.pixee.security.Filenames;
import java.awt.Color; import java.awt.Color;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
@@ -32,6 +31,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -106,7 +106,9 @@ public class WatermarkController {
return WebResponseUtils.pdfDocToWebResponse( return WebResponseUtils.pdfDocToWebResponse(
document, document,
Filenames.toSimpleFileName(pdfFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_watermarked.pdf"); Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_watermarked.pdf");
} }
private void addTextWatermark( private void addTextWatermark(

View File

@@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.web;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -33,6 +34,8 @@ public class AccountWebController {
return "redirect:/"; return "redirect:/";
} }
model.addAttribute("currentPage", "login");
if (request.getParameter("error") != null) { if (request.getParameter("error") != null) {
model.addAttribute("error", request.getParameter("error")); model.addAttribute("error", request.getParameter("error"));
@@ -53,6 +56,7 @@ public class AccountWebController {
public String showAddUserForm(Model model, Authentication authentication) { public String showAddUserForm(Model model, Authentication authentication) {
List<User> allUsers = userRepository.findAll(); List<User> allUsers = userRepository.findAll();
Iterator<User> iterator = allUsers.iterator(); Iterator<User> iterator = allUsers.iterator();
Map<String, String> roleDetails = Role.getAllRoleDetails();
while (iterator.hasNext()) { while (iterator.hasNext()) {
User user = iterator.next(); User user = iterator.next();
@@ -60,6 +64,7 @@ public class AccountWebController {
for (Authority authority : user.getAuthorities()) { for (Authority authority : user.getAuthorities()) {
if (authority.getAuthority().equals(Role.INTERNAL_API_USER.getRoleId())) { if (authority.getAuthority().equals(Role.INTERNAL_API_USER.getRoleId())) {
iterator.remove(); iterator.remove();
roleDetails.remove(Role.INTERNAL_API_USER.getRoleId());
break; // Break out of the inner loop once the user is removed break; // Break out of the inner loop once the user is removed
} }
} }
@@ -68,6 +73,7 @@ public class AccountWebController {
model.addAttribute("users", allUsers); model.addAttribute("users", allUsers);
model.addAttribute("currentUsername", authentication.getName()); model.addAttribute("currentUsername", authentication.getName());
model.addAttribute("roleDetails", roleDetails);
return "addUsers"; return "addUsers";
} }
@@ -112,6 +118,7 @@ public class AccountWebController {
model.addAttribute("role", user.get().getRolesAsString()); model.addAttribute("role", user.get().getRolesAsString());
model.addAttribute("settings", settingsJson); model.addAttribute("settings", settingsJson);
model.addAttribute("changeCredsFlag", user.get().isFirstLogin()); model.addAttribute("changeCredsFlag", user.get().isFirstLogin());
model.addAttribute("currentPage", "account");
} }
} else { } else {
return "redirect:/"; return "redirect:/";

View File

@@ -13,7 +13,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
@Tag(name = "Convert", description = "Convert APIs") @Tag(name = "Convert", description = "Convert APIs")
public class ConverterWebController { public class ConverterWebController {
@ConditionalOnExpression("#{bookFormatsInstalled}") @ConditionalOnExpression("#{bookAndHtmlFormatsInstalled}")
@GetMapping("/book-to-pdf") @GetMapping("/book-to-pdf")
@Hidden @Hidden
public String convertBookToPdfForm(Model model) { public String convertBookToPdfForm(Model model) {
@@ -21,7 +21,7 @@ public class ConverterWebController {
return "convert/book-to-pdf"; return "convert/book-to-pdf";
} }
@ConditionalOnExpression("#{bookFormatsInstalled}") @ConditionalOnExpression("#{bookAndHtmlFormatsInstalled}")
@GetMapping("/pdf-to-book") @GetMapping("/pdf-to-book")
@Hidden @Hidden
public String convertPdfToBookForm(Model model) { public String convertPdfToBookForm(Model model) {

View File

@@ -82,7 +82,7 @@ public class OtherWebController {
} }
public List<String> getAvailableTesseractLanguages() { public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tesseract-ocr/5/tessdata"; String tessdataDir = "/usr/share/tessdata";
File[] files = new File(tessdataDir).listFiles(); File[] files = new File(tessdataDir).listFiles();
if (files == null) { if (files == null) {
return Collections.emptyList(); return Collections.emptyList();

View File

@@ -210,7 +210,6 @@ public class ApplicationProperties {
private String rootURIPath; private String rootURIPath;
private String customStaticFilePath; private String customStaticFilePath;
private Integer maxFileSize; private Integer maxFileSize;
private CustomApplications customApplications;
private Boolean enableAlphaFunctionality; private Boolean enableAlphaFunctionality;
@@ -262,14 +261,6 @@ public class ApplicationProperties {
this.maxFileSize = maxFileSize; this.maxFileSize = maxFileSize;
} }
public CustomApplications getCustomApplications() {
return customApplications != null ? customApplications : new CustomApplications();
}
public void setCustomApplications(CustomApplications customApplications) {
this.customApplications = customApplications;
}
@Override @Override
public String toString() { public String toString() {
return "System [defaultLocale=" return "System [defaultLocale="
@@ -282,42 +273,10 @@ public class ApplicationProperties {
+ customStaticFilePath + customStaticFilePath
+ ", maxFileSize=" + ", maxFileSize="
+ maxFileSize + maxFileSize
+ ", customApplications="
+ customApplications
+ ", enableAlphaFunctionality=" + ", enableAlphaFunctionality="
+ enableAlphaFunctionality + enableAlphaFunctionality
+ "]"; + "]";
} }
public static class CustomApplications {
private boolean installBookFormats;
private boolean installAdvancedHtmlToPDF;
public boolean isInstallBookFormats() {
return installBookFormats;
}
public void setInstallBookFormats(boolean installBookFormats) {
this.installBookFormats = installBookFormats;
}
public boolean isInstallAdvancedHtmlToPDF() {
return installAdvancedHtmlToPDF;
}
public void setInstallAdvancedHtmlToPDF(boolean installAdvancedHtmlToPDF) {
this.installAdvancedHtmlToPDF = installAdvancedHtmlToPDF;
}
@Override
public String toString() {
return "CustomApplications [installBookFormats="
+ installBookFormats
+ ", installAdvancedHtmlToPDF="
+ installAdvancedHtmlToPDF
+ "]";
}
}
} }
public static class Ui { public static class Ui {

View File

@@ -1,34 +1,43 @@
package stirling.software.SPDF.model; package stirling.software.SPDF.model;
import java.util.LinkedHashMap;
import java.util.Map;
public enum Role { public enum Role {
// Unlimited access // Unlimited access
ADMIN("ROLE_ADMIN", Integer.MAX_VALUE, Integer.MAX_VALUE), ADMIN("ROLE_ADMIN", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.admin"),
// Unlimited access // Unlimited access
USER("ROLE_USER", Integer.MAX_VALUE, Integer.MAX_VALUE), USER("ROLE_USER", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.user"),
// 40 API calls Per Day, 40 web calls // 40 API calls Per Day, 40 web calls
LIMITED_API_USER("ROLE_LIMITED_API_USER", 40, 40), LIMITED_API_USER("ROLE_LIMITED_API_USER", 40, 40, "adminUserSettings.apiUser"),
// 20 API calls Per Day, 20 web calls // 20 API calls Per Day, 20 web calls
EXTRA_LIMITED_API_USER("ROLE_EXTRA_LIMITED_API_USER", 20, 20), EXTRA_LIMITED_API_USER("ROLE_EXTRA_LIMITED_API_USER", 20, 20, "adminUserSettings.extraApiUser"),
// 0 API calls per day and 20 web calls // 0 API calls per day and 20 web calls
WEB_ONLY_USER("ROLE_WEB_ONLY_USER", 0, 20), WEB_ONLY_USER("ROLE_WEB_ONLY_USER", 0, 20, "adminUserSettings.webOnlyUser"),
INTERNAL_API_USER("STIRLING-PDF-BACKEND-API-USER", Integer.MAX_VALUE, Integer.MAX_VALUE), INTERNAL_API_USER(
"STIRLING-PDF-BACKEND-API-USER",
Integer.MAX_VALUE,
Integer.MAX_VALUE,
"adminUserSettings.internalApiUser"),
DEMO_USER("ROLE_DEMO_USER", 100, 100); DEMO_USER("ROLE_DEMO_USER", 100, 100, "adminUserSettings.demoUser");
private final String roleId; private final String roleId;
private final int apiCallsPerDay; private final int apiCallsPerDay;
private final int webCallsPerDay; private final int webCallsPerDay;
private final String roleName;
Role(String roleId, int apiCallsPerDay, int webCallsPerDay) { Role(String roleId, int apiCallsPerDay, int webCallsPerDay, String roleName) {
this.roleId = roleId; this.roleId = roleId;
this.apiCallsPerDay = apiCallsPerDay; this.apiCallsPerDay = apiCallsPerDay;
this.webCallsPerDay = webCallsPerDay; this.webCallsPerDay = webCallsPerDay;
this.roleName = roleName;
} }
public String getRoleId() { public String getRoleId() {
@@ -43,6 +52,27 @@ public enum Role {
return webCallsPerDay; return webCallsPerDay;
} }
public String getRoleName() {
return roleName;
}
public static String getRoleNameByRoleId(String roleId) {
// Using the fromString method to get the Role enum based on the roleId
Role role = fromString(roleId);
// Return the roleName of the found Role enum
return role.getRoleName();
}
// Method to retrieve all role IDs and role names
public static Map<String, String> getAllRoleDetails() {
// Using LinkedHashMap to preserve order
Map<String, String> roleDetails = new LinkedHashMap<>();
for (Role role : Role.values()) {
roleDetails.put(role.getRoleId(), role.getRoleName());
}
return roleDetails;
}
public static Role fromString(String roleId) { public static Role fromString(String roleId) {
for (Role role : Role.values()) { for (Role role : Role.values()) {
if (role.getRoleId().equalsIgnoreCase(roleId)) { if (role.getRoleId().equalsIgnoreCase(roleId)) {

View File

@@ -44,6 +44,9 @@ public class User {
@Column(name = "isFirstLogin") @Column(name = "isFirstLogin")
private Boolean isFirstLogin = false; private Boolean isFirstLogin = false;
@Column(name = "roleName")
private String roleName;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user") @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user")
private Set<Authority> authorities = new HashSet<>(); private Set<Authority> authorities = new HashSet<>();
@@ -53,6 +56,10 @@ public class User {
@CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id")) @CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id"))
private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings. private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings.
public String getRoleName() {
return Role.getRoleNameByRoleId(getRolesAsString());
}
public boolean isFirstLogin() { public boolean isFirstLogin() {
return isFirstLogin != null && isFirstLogin; return isFirstLogin != null && isFirstLogin;
} }

View File

@@ -25,7 +25,7 @@ public class PDFWithPageNums extends PDFFile {
private String pageNumbers; private String pageNumbers;
@Hidden @Hidden
public List<Integer> getPageNumbersList() { public List<Integer> getPageNumbersList(boolean zeroCount) {
int pageCount = 0; int pageCount = 0;
try { try {
pageCount = Loader.loadPDF(getFileInput().getBytes()).getNumberOfPages(); pageCount = Loader.loadPDF(getFileInput().getBytes()).getNumberOfPages();
@@ -33,13 +33,13 @@ public class PDFWithPageNums extends PDFFile {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
return GeneralUtils.parsePageString(pageNumbers, pageCount); return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
} }
@Hidden @Hidden
public List<Integer> getPageNumbersList(PDDocument doc) { public List<Integer> getPageNumbersList(PDDocument doc, boolean zeroCount) {
int pageCount = 0; int pageCount = 0;
pageCount = doc.getNumberOfPages(); pageCount = doc.getNumberOfPages();
return GeneralUtils.parsePageString(pageNumbers, pageCount); return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
} }
} }

View File

@@ -15,4 +15,7 @@ public class SplitPdfBySectionsRequest extends PDFFile {
@Schema(description = "Number of vertical divisions for each PDF page", example = "2") @Schema(description = "Number of vertical divisions for each PDF page", example = "2")
private int verticalDivisions; private int verticalDivisions;
@Schema(description = "Merge the split documents into a single PDF", example = "true")
private boolean merge;
} }

View File

@@ -14,39 +14,4 @@ public class HTMLToPdfRequest extends PDFFile {
description = "Zoom level for displaying the website. Default is '1'.", description = "Zoom level for displaying the website. Default is '1'.",
defaultValue = "1") defaultValue = "1")
private float zoom; private float zoom;
@Schema(description = "Width of the page in centimeters.")
private Float pageWidth;
@Schema(description = "Height of the page in centimeters.")
private Float pageHeight;
@Schema(description = "Top margin of the page in millimeters.")
private Float marginTop;
@Schema(description = "Bottom margin of the page in millimeters.")
private Float marginBottom;
@Schema(description = "Left margin of the page in millimeters.")
private Float marginLeft;
@Schema(description = "Right margin of the page in millimeters.")
private Float marginRight;
@Schema(
description = "Enable or disable rendering of website background.",
allowableValues = {"Yes", "No"})
private String printBackground;
@Schema(
description =
"Enable or disable the default header. The default header includes the name of the page on the left and the page number on the right.",
allowableValues = {"Yes", "No"})
private String defaultHeader;
@Schema(
description = "Change the CSS media type of the page. Defaults to 'print'.",
allowableValues = {"none", "print", "screen"},
defaultValue = "print")
private String cssMediaType;
} }

View File

@@ -12,6 +12,6 @@ public class PdfToTextOrRTFRequest extends PDFFile {
@Schema( @Schema(
description = "The output Text or RTF format", description = "The output Text or RTF format",
allowableValues = {"rtf", "txt:Text"}) allowableValues = {"rtf", "txt"})
private String outputFormat; private String outputFormat;
} }

View File

@@ -6,11 +6,11 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFWithPageNums;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class AddStampRequest extends PDFFile { public class AddStampRequest extends PDFWithPageNums {
@Schema( @Schema(
description = "The stamp type (text or image)", description = "The stamp type (text or image)",

View File

@@ -1,9 +1,9 @@
package stirling.software.SPDF.utils; package stirling.software.SPDF.utils;
import io.github.pixee.security.ZipSecurity;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@@ -13,6 +13,8 @@ import java.util.stream.Stream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import io.github.pixee.security.ZipSecurity;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest; import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
@@ -33,95 +35,40 @@ public class FileToPdf {
tempInputFile = Files.createTempFile("input_", ".html"); tempInputFile = Files.createTempFile("input_", ".html");
Files.write(tempInputFile, fileBytes); Files.write(tempInputFile, fileBytes);
} else { } else {
tempInputFile = unzipAndGetMainHtml(fileBytes); tempInputFile = Files.createTempFile("input_", ".zip");
Files.write(tempInputFile, fileBytes);
} }
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
if (!htmlFormatsInstalled) { if (!htmlFormatsInstalled) {
command.add("weasyprint"); command.add("weasyprint");
} else {
command.add("wkhtmltopdf");
command.add("--enable-local-file-access");
command.add("--load-error-handling");
command.add("ignore");
command.add("--load-media-error-handling");
command.add("ignore");
command.add("--zoom");
command.add(String.valueOf(request.getZoom()));
// if custom zoom add zoom style direct to html
// https://github.com/wkhtmltopdf/wkhtmltopdf/issues/4900
if (request.getZoom() != 1.0) {
String htmlContent = new String(Files.readAllBytes(tempInputFile));
String zoomStyle = "<style>body { zoom: " + request.getZoom() + "; }</style>";
// Check for <head> tag, add style tag to associated tag
if (htmlContent.contains("<head>")) {
htmlContent = htmlContent.replace("<head>", "<head>" + zoomStyle);
} else if (htmlContent.contains("<html>")) {
// If no <head> tag, but <html> tag exists
htmlContent = htmlContent.replace("<html>", "<html>" + zoomStyle);
} else {
// If neither <head> nor <html> tags exist
htmlContent = zoomStyle + htmlContent;
}
// rewrite new html to file
Files.write(tempInputFile, htmlContent.getBytes(StandardCharsets.UTF_8));
}
if (request.getPageWidth() != null) {
command.add("--page-width");
command.add(request.getPageWidth() + "cm");
}
if (request.getPageHeight() != null) {
command.add("--page-height");
command.add(request.getPageHeight() + "cm");
}
if (request.getMarginTop() != null) {
command.add("--margin-top");
command.add(request.getMarginTop() + "mm");
}
// Repeat similar pattern for marginBottom, marginLeft, marginRight
if ("Yes".equalsIgnoreCase(request.getPrintBackground())) {
command.add("--background");
} else {
command.add("--no-background");
}
if ("Yes".equalsIgnoreCase(request.getDefaultHeader())) {
command.add("--default-header");
}
if ("print".equalsIgnoreCase(request.getCssMediaType())) {
command.add("--print-media-type");
} else if ("screen".equalsIgnoreCase(request.getCssMediaType())) {
command.add("--no-print-media-type");
}
}
command.add(tempInputFile.toString()); command.add(tempInputFile.toString());
command.add(tempOutputFile.toString()); command.add(tempOutputFile.toString());
ProcessExecutorResult returnCode;
if (fileName.endsWith(".zip")) {
if (htmlFormatsInstalled) {
// command.add(1, "--allow");
// command.add(2, tempInputFile.getParent().toString());
}
returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
.runCommandWithOutputHandling(
command, tempInputFile.getParent().toFile());
} else { } else {
command.add("ebook-convert");
command.add(tempInputFile.toString());
command.add(tempOutputFile.toString());
command.add("--paper-size");
command.add("a4");
if (request.getZoom() != 1.0) {
// Create a temporary CSS file
File tempCssFile = Files.createTempFile("customStyle", ".css").toFile();
try (FileWriter writer = new FileWriter(tempCssFile)) {
// Write the CSS rule to the file
writer.write("body { zoom: " + request.getZoom() + "; }");
}
command.add("--extra-css");
command.add(tempCssFile.getAbsolutePath());
}
}
ProcessExecutorResult returnCode;
returnCode = returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT) ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
.runCommandWithOutputHandling(command); .runCommandWithOutputHandling(command);
}
pdfBytes = Files.readAllBytes(tempOutputFile); pdfBytes = Files.readAllBytes(tempOutputFile);
} catch (IOException e) { } catch (IOException e) {
@@ -134,10 +81,6 @@ public class FileToPdf {
// Clean up temporary files // Clean up temporary files
Files.delete(tempOutputFile); Files.delete(tempOutputFile);
Files.delete(tempInputFile); Files.delete(tempInputFile);
if (fileName.endsWith(".zip")) {
GeneralUtils.deleteDirectory(tempInputFile.getParent());
}
} }
return pdfBytes; return pdfBytes;
@@ -145,7 +88,8 @@ public class FileToPdf {
private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException { private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException {
Path tempDirectory = Files.createTempDirectory("unzipped_"); Path tempDirectory = Files.createTempDirectory("unzipped_");
try (ZipInputStream zipIn = ZipSecurity.createHardenedInputStream(new ByteArrayInputStream(fileBytes))) { try (ZipInputStream zipIn =
ZipSecurity.createHardenedInputStream(new ByteArrayInputStream(fileBytes))) {
ZipEntry entry = zipIn.getNextEntry(); ZipEntry entry = zipIn.getNextEntry();
while (entry != null) { while (entry != null) {
Path filePath = tempDirectory.resolve(entry.getName()); Path filePath = tempDirectory.resolve(entry.getName());

View File

@@ -1,13 +1,10 @@
package stirling.software.SPDF.utils; package stirling.software.SPDF.utils;
import io.github.pixee.security.HostValidator;
import io.github.pixee.security.Urls;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -15,10 +12,14 @@ import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.HostValidator;
import io.github.pixee.security.Urls;
public class GeneralUtils { public class GeneralUtils {
public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException { public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
@@ -59,7 +60,8 @@ public class GeneralUtils {
public static boolean isValidURL(String urlStr) { public static boolean isValidURL(String urlStr) {
try { try {
Urls.create(urlStr, Urls.HTTP_PROTOCOLS, HostValidator.DENY_COMMON_INFRASTRUCTURE_TARGETS); Urls.create(
urlStr, Urls.HTTP_PROTOCOLS, HostValidator.DENY_COMMON_INFRASTRUCTURE_TARGETS);
return true; return true;
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
return false; return false;
@@ -114,17 +116,36 @@ public class GeneralUtils {
} }
public static List<Integer> parsePageString(String pageOrder, int totalPages) { public static List<Integer> parsePageString(String pageOrder, int totalPages) {
return parsePageList(pageOrder.split(","), totalPages); return parsePageString(pageOrder, totalPages, false);
}
public static List<Integer> parsePageString(
String pageOrder, int totalPages, boolean isOneBased) {
if (pageOrder == null || pageOrder.isEmpty()) {
return Collections.singletonList(1);
}
if (pageOrder.matches("\\d+")) {
// Convert the single number string to an integer and return it in a list
return Collections.singletonList(Integer.parseInt(pageOrder));
}
return parsePageList(pageOrder.split(","), totalPages, isOneBased);
} }
public static List<Integer> parsePageList(String[] pageOrderArr, int totalPages) { public static List<Integer> parsePageList(String[] pageOrderArr, int totalPages) {
return parsePageList(pageOrderArr, totalPages, false);
}
public static List<Integer> parsePageList(
String[] pageOrderArr, int totalPages, boolean isOneBased) {
List<Integer> newPageOrder = new ArrayList<>(); List<Integer> newPageOrder = new ArrayList<>();
int adjustmentFactor = isOneBased ? 1 : 0;
// loop through the page order array // loop through the page order array
for (String element : pageOrderArr) { for (String element : pageOrderArr) {
if ("all".equalsIgnoreCase(element)) { if ("all".equalsIgnoreCase(element)) {
for (int i = 0; i < totalPages; i++) { for (int i = 0; i < totalPages; i++) {
newPageOrder.add(i); newPageOrder.add(i + adjustmentFactor);
} }
// As all pages are already added, no need to check further // As all pages are already added, no need to check further
break; break;
@@ -155,7 +176,7 @@ public class GeneralUtils {
pageNum += constantExists ? constant : 0; pageNum += constantExists ? constant : 0;
if (pageNum <= totalPages && pageNum > 0) { if (pageNum <= totalPages && pageNum > 0) {
newPageOrder.add(pageNum - 1); newPageOrder.add(pageNum - adjustmentFactor);
} }
} }
} else if (element.contains("-")) { } else if (element.contains("-")) {
@@ -170,11 +191,11 @@ public class GeneralUtils {
// loop through the range of pages // loop through the range of pages
for (int j = start; j <= end; j++) { for (int j = start; j <= end; j++) {
// print the current index // print the current index
newPageOrder.add(j - 1); newPageOrder.add(j - adjustmentFactor);
} }
} else { } else {
// if the element is a single page // if the element is a single page
newPageOrder.add(Integer.parseInt(element) - 1); newPageOrder.add(Integer.parseInt(element) - adjustmentFactor);
} }
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.utils; package stirling.software.SPDF.utils;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@@ -21,6 +20,8 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
public class PDFToFile { public class PDFToFile {

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.utils; package stirling.software.SPDF.utils;
import io.github.pixee.security.Filenames;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage; import java.awt.image.RenderedImage;
@@ -38,6 +37,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
public class PdfUtils { public class PdfUtils {
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class); private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.utils; package stirling.software.SPDF.utils;
import io.github.pixee.security.BoundedLineReader;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -17,6 +16,8 @@ import java.util.concurrent.TimeUnit;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.github.pixee.security.BoundedLineReader;
public class ProcessExecutor { public class ProcessExecutor {
private static final Logger logger = LoggerFactory.getLogger(ProcessExecutor.class); private static final Logger logger = LoggerFactory.getLogger(ProcessExecutor.class);
@@ -110,7 +111,10 @@ public class ProcessExecutor {
process.getErrorStream(), process.getErrorStream(),
StandardCharsets.UTF_8))) { StandardCharsets.UTF_8))) {
String line; String line;
while ((line = BoundedLineReader.readLine(errorReader, 5_000_000)) != null) { while ((line =
BoundedLineReader.readLine(
errorReader, 5_000_000))
!= null) {
errorLines.add(line); errorLines.add(line);
if (liveUpdates) logger.info(line); if (liveUpdates) logger.info(line);
} }
@@ -131,7 +135,10 @@ public class ProcessExecutor {
process.getInputStream(), process.getInputStream(),
StandardCharsets.UTF_8))) { StandardCharsets.UTF_8))) {
String line; String line;
while ((line = BoundedLineReader.readLine(outputReader, 5_000_000)) != null) { while ((line =
BoundedLineReader.readLine(
outputReader, 5_000_000))
!= null) {
outputLines.add(line); outputLines.add(line);
if (liveUpdates) logger.info(line); if (liveUpdates) logger.info(line);
} }

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.utils; package stirling.software.SPDF.utils;
import io.github.pixee.security.Filenames;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder; import java.net.URLEncoder;
@@ -13,6 +12,8 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
public class WebResponseUtils { public class WebResponseUtils {
public static ResponseEntity<byte[]> boasToWebResponse( public static ResponseEntity<byte[]> boasToWebResponse(

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=اختر صورة
genericSubmit=إرسال genericSubmit=إرسال
processTimeWarning=تحذير: يمكن أن تستغرق هذه العملية ما يصل إلى دقيقة حسب حجم الملف processTimeWarning=تحذير: يمكن أن تستغرق هذه العملية ما يصل إلى دقيقة حسب حجم الملف
pageOrderPrompt=ترتيب الصفحات (أدخل قائمة بأرقام الصفحات مفصولة بفواصل): pageOrderPrompt=ترتيب الصفحات (أدخل قائمة بأرقام الصفحات مفصولة بفواصل):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=اذهب goToPage=اذهب
true=\u0635\u062D\u064A\u062D true=\u0635\u062D\u064A\u062D
false=\u062E\u0637\u0623 false=\u062E\u0637\u0623
@@ -19,6 +20,7 @@ save=\u062D\u0641\u0638
close=\u0625\u063A\u0644\u0627\u0642 close=\u0625\u063A\u0644\u0627\u0642
filesSelected=الملفات المحددة filesSelected=الملفات المحددة
noFavourites=لم تتم إضافة أي مفضلات noFavourites=لم تتم إضافة أي مفضلات
downloadComplete=Download Complete
bored=الانتظار بالملل؟ bored=الانتظار بالملل؟
alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629 alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629
downloadPdf=تنزيل PDF downloadPdf=تنزيل PDF
@@ -42,7 +44,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -120,7 +124,7 @@ account.accountSettings=Account Settings
account.adminSettings=Admin Settings - View and Add Users account.adminSettings=Admin Settings - View and Add Users
account.userControlSettings=User Control Settings account.userControlSettings=User Control Settings
account.changeUsername=Change Username account.changeUsername=Change Username
account.changeUsername=Change Username account.newUsername=New Username
account.password=Confirmation Password account.password=Confirmation Password
account.oldPassword=Old password account.oldPassword=Old password
account.newPassword=New Password account.newPassword=New Password
@@ -145,9 +149,11 @@ adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
############# #############
@@ -366,7 +372,7 @@ showJS.tags=JS
home.autoRedact.title=Auto Redact home.autoRedact.title=Auto Redact
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
showJS.tags=JS autoRedact.tags=Redact,Hide,black out,black,marker,hidden
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=Sanitize PDF sanitizePDF.title=Sanitize PDF
sanitizePDF.header=Sanitize a PDF file sanitizePDF.header=Sanitize a PDF file
@@ -621,6 +637,18 @@ compare.document.1=المستند 1
compare.document.2=المستند 2 compare.document.2=المستند 2
compare.submit=يقارن compare.submit=يقارن
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=تسجيل الدخول sign.title=تسجيل الدخول
@@ -866,7 +894,6 @@ changeMetadata.keywords=\u0627\u0644\u0643\u0644\u0645\u0627\u062A \u0627\u0644\
changeMetadata.modDate=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u062A\u0639\u062F\u064A\u0644 (yyyy / MM / dd HH: mm: ss): changeMetadata.modDate=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u062A\u0639\u062F\u064A\u0644 (yyyy / MM / dd HH: mm: ss):
changeMetadata.producer=\u0627\u0644\u0645\u0646\u062A\u062C: changeMetadata.producer=\u0627\u0644\u0645\u0646\u062A\u062C:
changeMetadata.subject=\u0627\u0644\u0645\u0648\u0636\u0648\u0639: changeMetadata.subject=\u0627\u0644\u0645\u0648\u0636\u0648\u0639:
changeMetadata.title=\u0627\u0644\u0639\u0646\u0648\u0627\u0646:
changeMetadata.trapped=\u0645\u062D\u0627\u0635\u0631: changeMetadata.trapped=\u0645\u062D\u0627\u0635\u0631:
changeMetadata.selectText.4=\u0628\u064A\u0627\u0646\u0627\u062A \u0648\u0635\u0641\u064A\u0629 \u0623\u062E\u0631\u0649: changeMetadata.selectText.4=\u0628\u064A\u0627\u0646\u0627\u062A \u0648\u0635\u0641\u064A\u0629 \u0623\u062E\u0631\u0649:
changeMetadata.selectText.5=\u0625\u0636\u0627\u0641\u0629 \u0625\u062F\u062E\u0627\u0644 \u0628\u064A\u0627\u0646\u0627\u062A \u0623\u0648\u0644\u064A\u0629 \u0645\u062E\u0635\u0635 changeMetadata.selectText.5=\u0625\u0636\u0627\u0641\u0629 \u0625\u062F\u062E\u0627\u0644 \u0628\u064A\u0627\u0646\u0627\u062A \u0623\u0648\u0644\u064A\u0629 \u0645\u062E\u0635\u0635
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=Изберете изображение(я)
genericSubmit=Подайте genericSubmit=Подайте
processTimeWarning=Предупреждение: Този процес може да отнеме до минута в зависимост от размера на файла processTimeWarning=Предупреждение: Този процес може да отнеме до минута в зависимост от размера на файла
pageOrderPrompt=Персонализиран ред на страниците (Въведете разделен със запетаи списък с номера на страници или функции като 2n+1): pageOrderPrompt=Персонализиран ред на страниците (Въведете разделен със запетаи списък с номера на страници или функции като 2n+1):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Давай goToPage=Давай
true=Вярно true=Вярно
false=Невярно false=Невярно
@@ -19,6 +20,7 @@ save=Съхранете
close=Затворете close=Затворете
filesSelected=избрани файлове filesSelected=избрани файлове
noFavourites=Няма добавени любими noFavourites=Няма добавени любими
downloadComplete=Download Complete
bored=Отекчени сте да чакате? bored=Отекчени сте да чакате?
alphabet=Азбука alphabet=Азбука
downloadPdf=Изтеглете PDF downloadPdf=Изтеглете PDF
@@ -42,7 +44,7 @@ red=Червено
green=Зелено green=Зелено
blue=Синьо blue=Синьо
custom=Персонализиране... custom=Персонализиране...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=Потребителят не е автентикира
userNotFoundMessage=Потребителят не е намерен userNotFoundMessage=Потребителят не е намерен
incorrectPasswordMessage=Текущата парола е неправилна. incorrectPasswordMessage=Текущата парола е неправилна.
usernameExistsMessage=Новият потребител вече съществува. usernameExistsMessage=Новият потребител вече съществува.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=Настройки на акаунта
changeCreds.title=Промяна на идентификационните данни changeCreds.title=Промяна на идентификационните данни
changeCreds.header=Актуализирайте данните за акаунта си changeCreds.header=Актуализирайте данните за акаунта си
changeCreds.changeUserAndPassword=Използвате идентификационни данни за вход по подразбиране. Моля, въведете нова парола (и потребителско име, ако искате) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Ново потребителско име changeCreds.newUsername=Ново потребителско име
changeCreds.oldPassword=Текуща парола changeCreds.oldPassword=Текуща парола
changeCreds.newPassword=Нова парола changeCreds.newPassword=Нова парола
@@ -120,7 +124,7 @@ account.accountSettings=Настройки на акаунта
account.adminSettings=Настройки на администратора - Преглед и добавяне на потребители account.adminSettings=Настройки на администратора - Преглед и добавяне на потребители
account.userControlSettings=Настройки за потребителски контрол account.userControlSettings=Настройки за потребителски контрол
account.changeUsername=Промени потребител account.changeUsername=Промени потребител
account.changeUsername=Промени потребител account.newUsername=Ново потребителско име
account.password=Парола за потвърждение account.password=Парола за потвърждение
account.oldPassword=Стара парола account.oldPassword=Стара парола
account.newPassword=Нова парола account.newPassword=Нова парола
@@ -145,8 +149,10 @@ adminUserSettings.roles=Роли
adminUserSettings.role=Роля adminUserSettings.role=Роля
adminUserSettings.actions=Действия adminUserSettings.actions=Действия
adminUserSettings.apiUser=Ограничен API потребител adminUserSettings.apiUser=Ограничен API потребител
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Само за уеб-потребител adminUserSettings.webOnlyUser=Само за уеб-потребител
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане
adminUserSettings.submit=Съхранете потребителя adminUserSettings.submit=Съхранете потребителя
@@ -362,11 +368,11 @@ PdfToSinglePage.tags=единична страница
home.showJS.title=Показване на Javascript home.showJS.title=Показване на Javascript
home.showJS.desc=Търси и показва всеки JS, инжектиран в PDF home.showJS.desc=Търси и показва всеки JS, инжектиран в PDF
showJS.tags=Редактиране,Скриване,затъмняване,черен,маркер,скрит showJS.tags=JS
home.autoRedact.title=Автоматично редактиране home.autoRedact.title=Автоматично редактиране
home.autoRedact.desc=Автоматично редактира (зачернява) текст в PDF въз основа на въведен текст home.autoRedact.desc=Автоматично редактира (зачернява) текст в PDF въз основа на въведен текст
showJS.tags=Редактиране,Скриване,затъмняване,черен,маркер,скрит autoRedact.tags=Редактиране,Скриване,затъмняване,черен,маркер,скрит
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=Дезинфектирай PDF sanitizePDF.title=Дезинфектирай PDF
sanitizePDF.header=Дезинфектира PDF файл sanitizePDF.header=Дезинфектира PDF файл
@@ -621,6 +637,18 @@ compare.document.1=Документ 1
compare.document.2=Документ 2 compare.document.2=Документ 2
compare.submit=Сравнявай compare.submit=Сравнявай
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Подпишете sign.title=Подпишете
@@ -866,7 +894,6 @@ changeMetadata.keywords=Ключови думи:
changeMetadata.modDate=Дата на промяна (гггг/ММ/дд ЧЧ:мм:сс): changeMetadata.modDate=Дата на промяна (гггг/ММ/дд ЧЧ:мм:сс):
changeMetadata.producer=Продуцент: changeMetadata.producer=Продуцент:
changeMetadata.subject=Тема: changeMetadata.subject=Тема:
changeMetadata.title=Заглавие:
changeMetadata.trapped=В капан: changeMetadata.trapped=В капан:
changeMetadata.selectText.4=Други метаданни: changeMetadata.selectText.4=Други метаданни:
changeMetadata.selectText.5=Добавяне на персонализиране метаданни changeMetadata.selectText.5=Добавяне на персонализиране метаданни
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=Selecciona Imatge(s)
genericSubmit=Envia genericSubmit=Envia
processTimeWarning=Alerta: Aquest procés pot tardar 1 minut depenent de la mida de l'arxiu processTimeWarning=Alerta: Aquest procés pot tardar 1 minut depenent de la mida de l'arxiu
pageOrderPrompt=Ordre de Pàgines (Llista separada per comes) : pageOrderPrompt=Ordre de Pàgines (Llista separada per comes) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Anar goToPage=Anar
true=Verdader true=Verdader
false=Fals false=Fals
@@ -19,6 +20,7 @@ save=Desa
close=Tanca close=Tanca
filesSelected=fitxers seleccionats filesSelected=fitxers seleccionats
noFavourites=No s'ha afegit cap favorit noFavourites=No s'ha afegit cap favorit
downloadComplete=Download Complete
bored=Avorrit esperant? bored=Avorrit esperant?
alphabet=Alfabet alphabet=Alfabet
downloadPdf=Descarregueu PDF downloadPdf=Descarregueu PDF
@@ -42,7 +44,7 @@ red=Vermell
green=Verd green=Verd
blue=Blau blue=Blau
custom=Personalitzat... custom=Personalitzat...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -120,7 +124,7 @@ account.accountSettings=Opcions del compte
account.adminSettings=Opcions d'Admin - Veure i afegir usuaris account.adminSettings=Opcions d'Admin - Veure i afegir usuaris
account.userControlSettings=Opcions de Control d'Usuari account.userControlSettings=Opcions de Control d'Usuari
account.changeUsername=Canvia nom usuari account.changeUsername=Canvia nom usuari
account.changeUsername=Canvia nom usuari account.newUsername=Nom d'usuari nou
account.password=Confirma contrasenya account.password=Confirma contrasenya
account.oldPassword=Password Antic account.oldPassword=Password Antic
account.newPassword=Password Nou account.newPassword=Password Nou
@@ -145,9 +149,11 @@ adminUserSettings.roles=Rols
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Accions adminUserSettings.actions=Accions
adminUserSettings.apiUser=Usuari amb API limitada adminUserSettings.apiUser=Usuari amb API limitada
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Usuari només WEB adminUserSettings.webOnlyUser=Usuari només WEB
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Desar Usuari adminUserSettings.submit=Desar Usuari
############# #############
@@ -366,7 +372,7 @@ showJS.tags=JS
home.autoRedact.title=Auto Redact home.autoRedact.title=Auto Redact
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
showJS.tags=JS autoRedact.tags=Redact,Hide,black out,black,marker,hidden
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=Sanitize PDF sanitizePDF.title=Sanitize PDF
sanitizePDF.header=Sanitize a PDF file sanitizePDF.header=Sanitize a PDF file
@@ -621,6 +637,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Comparar compare.submit=Comparar
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sign sign.title=Sign
@@ -866,7 +894,6 @@ changeMetadata.keywords=Keywords:
changeMetadata.modDate=Data Modificació (yyyy/MM/dd HH:mm:ss): changeMetadata.modDate=Data Modificació (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=Productor: changeMetadata.producer=Productor:
changeMetadata.subject=Assumpte: changeMetadata.subject=Assumpte:
changeMetadata.title=Títol:
changeMetadata.trapped=Atrapat: changeMetadata.trapped=Atrapat:
changeMetadata.selectText.4=Altres Metadades: changeMetadata.selectText.4=Altres Metadades:
changeMetadata.selectText.5=Afegir entrada personalizada changeMetadata.selectText.5=Afegir entrada personalizada
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -11,6 +11,7 @@ imgPrompt=Wählen Sie ein Bild
genericSubmit=Einreichen genericSubmit=Einreichen
processTimeWarning=Achtung: Abhängig von der Dateigröße kann dieser Prozess bis zu einer Minute dauern processTimeWarning=Achtung: Abhängig von der Dateigröße kann dieser Prozess bis zu einer Minute dauern
pageOrderPrompt=Seitenreihenfolge (Geben Sie eine durch Komma getrennte Liste von Seitenzahlen ein): pageOrderPrompt=Seitenreihenfolge (Geben Sie eine durch Komma getrennte Liste von Seitenzahlen ein):
pageSelectionPrompt=Benutzerdefinierte Seitenauswahl (Geben Sie eine durch Kommas getrennte Liste von Seitenzahlen 1,5,6 oder Funktionen wie 2n+1 ein):
goToPage=Los goToPage=Los
true=Wahr true=Wahr
false=Falsch false=Falsch
@@ -19,6 +20,7 @@ save=Speichern
close=Schließen close=Schließen
filesSelected=Dateien ausgewählt filesSelected=Dateien ausgewählt
noFavourites=Keine Favoriten hinzugefügt noFavourites=Keine Favoriten hinzugefügt
downloadComplete=Download Complete
bored=Langeweile beim Warten? bored=Langeweile beim Warten?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=PDF herunterladen downloadPdf=PDF herunterladen
@@ -42,38 +44,40 @@ red=Rot
green=Grün green=Grün
blue=Blau blue=Blau
custom=benutzerdefiniert... custom=benutzerdefiniert...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=In Arbeit, funktioniert möglicherweise nicht oder ist fehlerhaft. Bitte melden Sie alle Probleme!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Ja
no=No no=Nein
changedCredsMessage=Anmeldedaten geändert! changedCredsMessage=Anmeldedaten geändert!
notAuthenticatedMessage=Benutzer nicht authentifiziert. notAuthenticatedMessage=Benutzer nicht authentifiziert.
userNotFoundMessage=Benutzer nicht gefunden. userNotFoundMessage=Benutzer nicht gefunden.
incorrectPasswordMessage=Das Passwort ist falsch. incorrectPasswordMessage=Das Passwort ist falsch.
usernameExistsMessage=Neuer Benutzername existiert bereits. usernameExistsMessage=Neuer Benutzername existiert bereits.
deleteCurrentUserMessage=Der aktuell angemeldete Benutzer kann nicht gelöscht werden.
deleteUsernameExistsMessage=Der Benutzername existiert nicht und kann nicht gelöscht werden.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline-Menü (Alpha)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Benutzerdefinierter Upload
pipeline.configureButton=Configure pipeline.configureButton=Konfigurieren
pipeline.defaultOption=Custom pipeline.defaultOption=Benutzerdefiniert
pipeline.submitButton=Submit pipeline.submitButton=Speichern
###################### ######################
# Pipeline Options # # Pipeline Options #
###################### ######################
pipelineOptions.header=Pipeline Configuration pipelineOptions.header=Pipeline-Konfiguration
pipelineOptions.pipelineNameLabel=Pipeline Name pipelineOptions.pipelineNameLabel=Pipeline-Name
pipelineOptions.saveSettings=Save Operation Settings pipelineOptions.saveSettings=Save Operation Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here pipelineOptions.pipelineNamePrompt=Geben Sie hier den Namen der Pipeline ein
pipelineOptions.selectOperation=Select Operation pipelineOptions.selectOperation=Vorgang auswählen
pipelineOptions.addOperationButton=Add operation pipelineOptions.addOperationButton=Vorgang hinzufügen
pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download pipelineOptions.saveButton=Downloaden
pipelineOptions.validateButton=Validate pipelineOptions.validateButton=Validieren
@@ -106,7 +110,7 @@ settings.accountSettings=Kontoeinstellungen
changeCreds.title=Anmeldeinformationen ändern changeCreds.title=Anmeldeinformationen ändern
changeCreds.header=Aktualisieren Sie Ihre Kontodaten changeCreds.header=Aktualisieren Sie Ihre Kontodaten
changeCreds.changeUserAndPassword=Sie verwenden Standard-Anmeldeinformationen. Bitte geben Sie ein neues Passwort (und ggf. einen Benutzernamen) ein. changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Neuer Benutzername changeCreds.newUsername=Neuer Benutzername
changeCreds.oldPassword=Aktuelles Passwort changeCreds.oldPassword=Aktuelles Passwort
changeCreds.newPassword=Neues Passwort changeCreds.newPassword=Neues Passwort
@@ -120,11 +124,11 @@ account.accountSettings=Kontoeinstellungen
account.adminSettings=Admin Einstellungen - Benutzer anzeigen und hinzufügen account.adminSettings=Admin Einstellungen - Benutzer anzeigen und hinzufügen
account.userControlSettings=Benutzerkontrolle account.userControlSettings=Benutzerkontrolle
account.changeUsername=Benutzername ändern account.changeUsername=Benutzername ändern
account.changeUsername=Benutzername ändern account.newUsername=Neuer Benutzername
account.password=Bestätigungspasswort account.password=Bestätigungspasswort
account.oldPassword=Altes Passwort account.oldPassword=Altes Passwort
account.newPassword=Neues Passwort account.newPassword=Neues Passwort
account.changePassword=Password ändern account.changePassword=Passwort ändern
account.confirmNewPassword=Neues Passwort bestätigen account.confirmNewPassword=Neues Passwort bestätigen
account.signOut=Abmelden account.signOut=Abmelden
account.yourApiKey=Dein API Schlüssel account.yourApiKey=Dein API Schlüssel
@@ -145,8 +149,10 @@ adminUserSettings.roles=Rollen
adminUserSettings.role=Rolle adminUserSettings.role=Rolle
adminUserSettings.actions=Aktion adminUserSettings.actions=Aktion
adminUserSettings.apiUser=Eingeschränkter API-Benutzer adminUserSettings.apiUser=Eingeschränkter API-Benutzer
adminUserSettings.extraApiUser=Zusätzlicher eingeschränkter API-Benutzer
adminUserSettings.webOnlyUser=Nur Web-Benutzer adminUserSettings.webOnlyUser=Nur Web-Benutzer
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo-Benutzer (Keine benutzerdefinierten Einstellungen)
adminUserSettings.internalApiUser=Interner API-Benutzer
adminUserSettings.forceChange=Benutzer dazu zwingen, Benutzernamen/Passwort bei der Anmeldung zu ändern adminUserSettings.forceChange=Benutzer dazu zwingen, Benutzernamen/Passwort bei der Anmeldung zu ändern
adminUserSettings.submit=Benutzer speichern adminUserSettings.submit=Benutzer speichern
@@ -283,8 +289,8 @@ home.removeBlanks.title=Leere Seiten entfernen
home.removeBlanks.desc=Erkennt und entfernt leere Seiten aus einem Dokument home.removeBlanks.desc=Erkennt und entfernt leere Seiten aus einem Dokument
removeBlanks.tags=cleanup,streamline,non-content,organize removeBlanks.tags=cleanup,streamline,non-content,organize
home.removeAnnotations.title=Remove Annotations home.removeAnnotations.title=Anmerkungen entfernen
home.removeAnnotations.desc=Removes all comments/annotations from a PDF home.removeAnnotations.desc=Entfernt alle Kommentare/Anmerkungen aus einem PDF
removeAnnotations.tags=comments,highlight,notes,markup,remove removeAnnotations.tags=comments,highlight,notes,markup,remove
home.compare.title=Vergleichen home.compare.title=Vergleichen
@@ -304,7 +310,7 @@ home.scalePages.desc=Größe/Skalierung der Seite und/oder des Inhalts ändern
scalePages.tags=resize,modify,dimension,adapt scalePages.tags=resize,modify,dimension,adapt
home.pipeline.title=Pipeline (Fortgeschritten) home.pipeline.title=Pipeline (Fortgeschritten)
home.pipeline.desc=Mehrere Aktionen auf ein PDF anwenden, definiert durch einen Pipeline Skript home.pipeline.desc=Mehrere Aktionen auf ein PDF anwenden, definiert durch ein Pipeline Skript
pipeline.tags=automate,sequence,scripted,batch-process pipeline.tags=automate,sequence,scripted,batch-process
home.add-page-numbers.title=Seitenzahlen hinzufügen home.add-page-numbers.title=Seitenzahlen hinzufügen
@@ -366,7 +372,7 @@ showJS.tags=JS
home.autoRedact.title=Automatisch zensieren/schwärzen home.autoRedact.title=Automatisch zensieren/schwärzen
home.autoRedact.desc=Automatisches Zensieren (Schwärzen) von Text in einer PDF-Datei basierend auf dem eingegebenen Text home.autoRedact.desc=Automatisches Zensieren (Schwärzen) von Text in einer PDF-Datei basierend auf dem eingegebenen Text
showJS.tags=zensieren,schwärzen autoRedact.tags=zensieren,schwärzen
home.tableExtraxt.title=Tabelle extrahieren home.tableExtraxt.title=Tabelle extrahieren
home.tableExtraxt.desc=Tabelle aus PDF in CSV extrahieren home.tableExtraxt.desc=Tabelle aus PDF in CSV extrahieren
@@ -386,11 +392,20 @@ home.split-by-sections.title=PDF in Abschnitte teilen
home.split-by-sections.desc=Teilen Sie jede Seite einer PDF-Datei in kleinere horizontale und vertikale Abschnitte auf home.split-by-sections.desc=Teilen Sie jede Seite einer PDF-Datei in kleinere horizontale und vertikale Abschnitte auf
split-by-sections.tags=abschnitte,teilen,bearbeiten split-by-sections.tags=abschnitte,teilen,bearbeiten
home.AddStampRequest.title=Add Stamp to PDF home.AddStampRequest.title=Stempel zu PDF hinzufügen
home.AddStampRequest.desc=Add text or add image stamps at set locations home.AddStampRequest.desc=Fügen Sie an festgelegten Stellen Text oder Bildstempel hinzu
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -466,37 +481,38 @@ HTMLToPDF.header=HTML zu PDF
HTMLToPDF.help=Akzeptiert HTML-Dateien und ZIPs mit html/css/images etc. HTMLToPDF.help=Akzeptiert HTML-Dateien und ZIPs mit html/css/images etc.
HTMLToPDF.submit=Konvertieren HTMLToPDF.submit=Konvertieren
HTMLToPDF.credit=Verwendet WeasyPrint HTMLToPDF.credit=Verwendet WeasyPrint
HTMLToPDF.zoom=Zoom level for displaying the website. HTMLToPDF.zoom=Zoomstufe zur Darstellung der Website.
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default) HTMLToPDF.pageWidth=Breite der Seite in Zentimetern. (Leer auf Standard)
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default) HTMLToPDF.pageHeight=Höhe der Seite in Zentimetern. (Leer auf Standard)
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default) HTMLToPDF.marginTop=Oberer Rand der Seite in Millimetern. (Leer auf Standard)
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default) HTMLToPDF.marginBottom=Unterer Rand der Seite in Millimetern. (Leer auf Standard)
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default) HTMLToPDF.marginLeft=Linker Rand der Seite in Millimetern. (Leer auf Standard)
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default) HTMLToPDF.marginRight=Linker Rand der Seite in Millimetern. (Leer auf Standard)
HTMLToPDF.printBackground=Render the background of websites. HTMLToPDF.printBackground=Den Hintergrund der Website rendern.
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number) HTMLToPDF.defaultHeader=Standardkopfzeile aktivieren (Name und Seitenzahl)
HTMLToPDF.cssMediaType=Change the CSS media type of the page. HTMLToPDF.cssMediaType=CSS-Medientyp der Seite ändern.
HTMLToPDF.none=None HTMLToPDF.none=Keine
HTMLToPDF.print=Print HTMLToPDF.print=Drucken
HTMLToPDF.screen=Screen HTMLToPDF.screen=Bildschirm
#AddStampRequest #AddStampRequest
AddStampRequest.header=Stamp PDF AddStampRequest.header=PDF Stempel
AddStampRequest.title=Stamp PDF AddStampRequest.title=PDF Stempel
AddStampRequest.stampType=Stamp Type AddStampRequest.stampType=Stempeltyp
AddStampRequest.stampText=Stamp Text AddStampRequest.stampText=Stempeltext
AddStampRequest.stampImage=Stamp Image AddStampRequest.stampImage=Stampelbild
AddStampRequest.alphabet=Alphabet AddStampRequest.alphabet=Alphabet
AddStampRequest.fontSize=Font/Image Size AddStampRequest.fontSize=Schriftart/Bildgröße
AddStampRequest.rotation=Rotation AddStampRequest.rotation=Rotation
AddStampRequest.opacity=Opacity AddStampRequest.opacity=Deckkraft
AddStampRequest.position=Position AddStampRequest.position=Position
AddStampRequest.overrideX=Override X Coordinate AddStampRequest.overrideX=X-Koordinate überschreiben
AddStampRequest.overrideY=Override Y Coordinate AddStampRequest.overrideY=Y-Koordinate überschreiben
AddStampRequest.customMargin=Custom Margin AddStampRequest.customMargin=Benutzerdefinierter Rand
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Benutzerdefinierte Textfarbe
AddStampRequest.submit=Submit AddStampRequest.submit=Abschicken
#sanitizePDF #sanitizePDF
sanitizePDF.title=PDF Bereinigen sanitizePDF.title=PDF Bereinigen
@@ -548,7 +564,7 @@ crop.submit=Abschicken
#autoSplitPDF #autoSplitPDF
autoSplitPDF.title=PDF automatisch teilen autoSplitPDF.title=PDF automatisch teilen
autoSplitPDF.header=PDF automatisch teilen autoSplitPDF.header=PDF automatisch teilen
autoSplitPDF.description=Drucken Sie, fügen Sie ein, scannen Sie, laden Sie hoch, und lassen Sie uns Ihre Dokumente automatisch trennen. Kein manuelles Sortieren erforderlich. autoSplitPDF.description=Drucken Sie, fügen Sie ein, scannen Sie, laden Sie hoch und lassen Sie uns Ihre Dokumente automatisch trennen. Kein manuelles Sortieren erforderlich.
autoSplitPDF.selectText.1=Drucken Sie einige Trennblätter aus (schwarz/weiß ist ausreichend). autoSplitPDF.selectText.1=Drucken Sie einige Trennblätter aus (schwarz/weiß ist ausreichend).
autoSplitPDF.selectText.2=Scannen Sie alle Dokumente auf einmal, indem Sie das Trennblatt zwischen die Dokumente einlegen. autoSplitPDF.selectText.2=Scannen Sie alle Dokumente auf einmal, indem Sie das Trennblatt zwischen die Dokumente einlegen.
autoSplitPDF.selectText.3=Laden Sie die einzelne große gescannte PDF-Datei hoch und überlassen Sie Stirling PDF den Rest. autoSplitPDF.selectText.3=Laden Sie die einzelne große gescannte PDF-Datei hoch und überlassen Sie Stirling PDF den Rest.
@@ -568,7 +584,7 @@ pipeline.title=Pipeline
pageLayout.title=Mehrseitiges Layout pageLayout.title=Mehrseitiges Layout
pageLayout.header=Mehrseitiges Layout pageLayout.header=Mehrseitiges Layout
pageLayout.pagesPerSheet=Seiten pro Blatt: pageLayout.pagesPerSheet=Seiten pro Blatt:
pageLayout.addBorder=Add Borders pageLayout.addBorder=Ränder hinzufügen
pageLayout.submit=Abschicken pageLayout.submit=Abschicken
@@ -584,11 +600,11 @@ scalePages.submit=Abschicken
certSign.title=Zertifikatsignierung certSign.title=Zertifikatsignierung
certSign.header=Signieren Sie ein PDF mit Ihrem Zertifikat (in Arbeit) certSign.header=Signieren Sie ein PDF mit Ihrem Zertifikat (in Arbeit)
certSign.selectPDF=Wählen Sie eine PDF-Datei zum Signieren aus: certSign.selectPDF=Wählen Sie eine PDF-Datei zum Signieren aus:
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below. certSign.jksNote=Hinweis: Wenn Ihr Zertifikatstyp unten nicht aufgeführt ist, konvertieren Sie ihn bitte mit dem Befehlszeilentool keytool in eine Java Keystore-Datei (.jks). Wählen Sie dann unten die Option „.jks-Datei“ aus.
certSign.selectKey=Wählen Sie Ihre private Schlüsseldatei aus (PKCS#8-Format, könnte .pem oder .der sein): certSign.selectKey=Wählen Sie Ihre private Schlüsseldatei aus (PKCS#8-Format, könnte .pem oder .der sein):
certSign.selectCert=Wählen Sie Ihre Zertifikatsdatei aus (X.509-Format, könnte .pem oder .der sein): certSign.selectCert=Wählen Sie Ihre Zertifikatsdatei aus (X.509-Format, könnte .pem oder .der sein):
certSign.selectP12=Wählen Sie Ihre PKCS#12-Keystore-Datei (.p12 oder .pfx) aus (optional, falls angegeben, sollte sie Ihren privaten Schlüssel und Ihr Zertifikat enthalten): certSign.selectP12=Wählen Sie Ihre PKCS#12-Keystore-Datei (.p12 oder .pfx) aus (optional, falls angegeben, sollte sie Ihren privaten Schlüssel und Ihr Zertifikat enthalten):
certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore): certSign.selectJKS=Wählen Sie Ihre Java Keystore-Datei (.jks oder .keystore):
certSign.certType=Zertifikattyp certSign.certType=Zertifikattyp
certSign.password=Geben Sie Ihr Keystore- oder Private-Key-Passwort ein (falls vorhanden): certSign.password=Geben Sie Ihr Keystore- oder Private-Key-Passwort ein (falls vorhanden):
certSign.showSig=Signatur anzeigen certSign.showSig=Signatur anzeigen
@@ -621,6 +637,18 @@ compare.document.1=Dokument 1
compare.document.2=Dokument 2 compare.document.2=Dokument 2
compare.submit=Vergleichen compare.submit=Vergleichen
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Signieren sign.title=Signieren
@@ -700,7 +728,7 @@ compress.selectText.1=Manueller Modus Von 1 bis 4
compress.selectText.2=Optimierungsstufe: compress.selectText.2=Optimierungsstufe:
compress.selectText.3=4 (Schrecklich für Textbilder) compress.selectText.3=4 (Schrecklich für Textbilder)
compress.selectText.4=Automatischer Modus Passt die Qualität automatisch an, um das PDF auf die exakte Größe zu bringen compress.selectText.4=Automatischer Modus Passt die Qualität automatisch an, um das PDF auf die exakte Größe zu bringen
compress.selectText.5=Erwartete PDF-Größe (z. B. 25 MB, 10,8 MB, 25 KB) compress.selectText.5=Erwartete PDF-Größe (z.B. 25 MB, 10,8 MB, 25 KB)
compress.submit=Komprimieren compress.submit=Komprimieren
@@ -731,8 +759,8 @@ multiTool.title=PDF-Multitool
multiTool.header=PDF-Multitool multiTool.header=PDF-Multitool
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=PDF anzeigen
viewPdf.header=View PDF viewPdf.header=PDF anzeigen
#pageRemover #pageRemover
pageRemover.title=Seiten entfernen pageRemover.title=Seiten entfernen
@@ -767,10 +795,10 @@ split.submit=Aufteilen
imageToPDF.title=Bild zu PDF imageToPDF.title=Bild zu PDF
imageToPDF.header=Bild zu PDF imageToPDF.header=Bild zu PDF
imageToPDF.submit=Umwandeln imageToPDF.submit=Umwandeln
imageToPDF.selectLabel=Image Fit Options imageToPDF.selectLabel=Bild anpassen
imageToPDF.fillPage=Fill Page imageToPDF.fillPage=Seite füllen
imageToPDF.fitDocumentToImage=Fit Page to Image imageToPDF.fitDocumentToImage=Seite an Bild anpassen
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios imageToPDF.maintainAspectRatio=Seitenverhältnisse beibehalten
imageToPDF.selectText.2=PDF automatisch drehen imageToPDF.selectText.2=PDF automatisch drehen
imageToPDF.selectText.3=Mehrere Dateien verarbeiten (nur aktiv, wenn Sie mit mehreren Bildern arbeiten) imageToPDF.selectText.3=Mehrere Dateien verarbeiten (nur aktiv, wenn Sie mit mehreren Bildern arbeiten)
imageToPDF.selectText.4=In ein einziges PDF zusammenführen imageToPDF.selectText.4=In ein einziges PDF zusammenführen
@@ -860,13 +888,12 @@ changeMetadata.selectText.1=Bitte bearbeiten Sie die Variablen, die Sie ändern
changeMetadata.selectText.2=Alle Metadaten löschen changeMetadata.selectText.2=Alle Metadaten löschen
changeMetadata.selectText.3=Benutzerdefinierte Metadaten anzeigen: changeMetadata.selectText.3=Benutzerdefinierte Metadaten anzeigen:
changeMetadata.author=Autor: changeMetadata.author=Autor:
changeMetadata.creationDate=Erstellungsdatum (jjjj/MM/tt HH:mm:ss): changeMetadata.creationDate=Erstellungsdatum (JJJJ/MM/TT HH:mm:ss):
changeMetadata.creator=Ersteller: changeMetadata.creator=Ersteller:
changeMetadata.keywords=Schlüsselwörter: changeMetadata.keywords=Schlüsselwörter:
changeMetadata.modDate=Änderungsdatum (JJJJ/MM/TT HH:mm:ss): changeMetadata.modDate=Änderungsdatum (JJJJ/MM/TT HH:mm:ss):
changeMetadata.producer=Produzent: changeMetadata.producer=Produzent:
changeMetadata.subject=Betreff: changeMetadata.subject=Betreff:
changeMetadata.title=Titel:
changeMetadata.trapped=Gefangen: changeMetadata.trapped=Gefangen:
changeMetadata.selectText.4=Andere Metadaten: changeMetadata.selectText.4=Andere Metadaten:
changeMetadata.selectText.5=Benutzerdefinierten Metadateneintrag hinzufügen changeMetadata.selectText.5=Benutzerdefinierten Metadateneintrag hinzufügen
@@ -930,7 +957,7 @@ split-by-size-or-count.type.size=Nach Größe
split-by-size-or-count.type.pageCount=Nach Anzahl Seiten split-by-size-or-count.type.pageCount=Nach Anzahl Seiten
split-by-size-or-count.type.docCount=Nach Anzahl Dokumenten split-by-size-or-count.type.docCount=Nach Anzahl Dokumenten
split-by-size-or-count.value.label=Wert eingeben split-by-size-or-count.value.label=Wert eingeben
split-by-size-or-count.value.placeholder=Größe eingeben (z. B.: 2MB oder 3KB) oder Anzahl (z. B.: 5) split-by-size-or-count.value.placeholder=Größe eingeben (z.B.: 2MB oder 3KB) oder Anzahl (z.B.: 5)
split-by-size-or-count.submit=Erstellen split-by-size-or-count.submit=Erstellen
@@ -943,7 +970,7 @@ overlay-pdfs.mode.sequential=Sequentielles Overlay
overlay-pdfs.mode.interleaved=Verschachteltes Overlay overlay-pdfs.mode.interleaved=Verschachteltes Overlay
overlay-pdfs.mode.fixedRepeat=Feste-Wiederholung Overlay overlay-pdfs.mode.fixedRepeat=Feste-Wiederholung Overlay
overlay-pdfs.counts.label=Overlay Anzahl (für Feste-Wiederholung) overlay-pdfs.counts.label=Overlay Anzahl (für Feste-Wiederholung)
overlay-pdfs.counts.placeholder=Komma-separierte Anzahl eingeben (z. B.: 2,3,1) overlay-pdfs.counts.placeholder=Komma-separierte Anzahl eingeben (z.B.: 2,3,1)
overlay-pdfs.position.label=Overlay Position auswählen overlay-pdfs.position.label=Overlay Position auswählen
overlay-pdfs.position.foreground=Vordergrund overlay-pdfs.position.foreground=Vordergrund
overlay-pdfs.position.background=Hintergrund overlay-pdfs.position.background=Hintergrund
@@ -958,13 +985,14 @@ split-by-sections.vertical.label=Vertikale Teiler
split-by-sections.horizontal.placeholder=Anzahl horizontaler Teiler eingeben split-by-sections.horizontal.placeholder=Anzahl horizontaler Teiler eingeben
split-by-sections.vertical.placeholder=Anzahl vertikaler Teiler eingeben split-by-sections.vertical.placeholder=Anzahl vertikaler Teiler eingeben
split-by-sections.submit=PDF teilen split-by-sections.submit=PDF teilen
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Lizenzen
licenses.title=3rd Party Licenses licenses.title=Lizenzen von Drittanbietern
licenses.header=3rd Party Licenses licenses.header=Lizenzen von Drittanbietern
licenses.module=Module licenses.module=Modul
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=Lizenz

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u0395\u03B9\u03BA\u03CC\u0
genericSubmit=\u03A5\u03C0\u03BF\u03B2\u03BF\u03BB\u03AE genericSubmit=\u03A5\u03C0\u03BF\u03B2\u03BF\u03BB\u03AE
processTimeWarning=\u03A0\u03C1\u03BF\u03C3\u03BF\u03C7\u03AE: \u0391\u03C5\u03C4\u03AE \u03B7 \u03B4\u03B9\u03B1\u03B4\u03B9\u03BA\u03B1\u03C3\u03AF\u03B1 \u03BC\u03C0\u03BF\u03C1\u03B5\u03AF \u03BD\u03B1 \u03B4\u03B9\u03B1\u03C1\u03BA\u03AD\u03C3\u03B5\u03B9 \u03AD\u03C9\u03C2 \u03BA\u03B1\u03B9 \u03AD\u03BD\u03B1 \u03BB\u03B5\u03C0\u03C4\u03CC \u03B1\u03BD\u03AC\u03BB\u03BF\u03B3\u03B1 \u03BC\u03B5 \u03C4\u03BF \u03BC\u03AD\u03B3\u03B5\u03B8\u03BF\u03C2 \u03C4\u03BF\u03C5 \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5 processTimeWarning=\u03A0\u03C1\u03BF\u03C3\u03BF\u03C7\u03AE: \u0391\u03C5\u03C4\u03AE \u03B7 \u03B4\u03B9\u03B1\u03B4\u03B9\u03BA\u03B1\u03C3\u03AF\u03B1 \u03BC\u03C0\u03BF\u03C1\u03B5\u03AF \u03BD\u03B1 \u03B4\u03B9\u03B1\u03C1\u03BA\u03AD\u03C3\u03B5\u03B9 \u03AD\u03C9\u03C2 \u03BA\u03B1\u03B9 \u03AD\u03BD\u03B1 \u03BB\u03B5\u03C0\u03C4\u03CC \u03B1\u03BD\u03AC\u03BB\u03BF\u03B3\u03B1 \u03BC\u03B5 \u03C4\u03BF \u03BC\u03AD\u03B3\u03B5\u03B8\u03BF\u03C2 \u03C4\u03BF\u03C5 \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5
pageOrderPrompt=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03C3\u03BC\u03AD\u03BD\u03B7 \u03A3\u03B5\u03B9\u03C1\u03AC \u03A3\u03B5\u03BB\u03AF\u03B4\u03B1\u03C2 (\u03A0\u03C1\u03BF\u03C3\u03B8\u03AD\u03C3\u03C4\u03B5 \u03BC\u03AF\u03B1 \u03BB\u03AF\u03C3\u03C4\u03B5 \u03B1\u03C0\u03BF \u03B1\u03C1\u03B9\u03B8\u03BC\u03BF\u03CD\u03C2 \u03C3\u03B5\u03BB\u03B9\u03B4\u03CE\u03BD, \u03C7\u03C9\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03B5\u03C2 \u03BC\u03B5 \u03BA\u03CC\u03BC\u03BC\u03B1 \u03AE \u03C3\u03C5\u03BD\u03B1\u03C1\u03C4\u03AE\u03C3\u03B5\u03B9\u03C2 \u03CC\u03C0\u03C9\u03C2 2n+1) : pageOrderPrompt=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03C3\u03BC\u03AD\u03BD\u03B7 \u03A3\u03B5\u03B9\u03C1\u03AC \u03A3\u03B5\u03BB\u03AF\u03B4\u03B1\u03C2 (\u03A0\u03C1\u03BF\u03C3\u03B8\u03AD\u03C3\u03C4\u03B5 \u03BC\u03AF\u03B1 \u03BB\u03AF\u03C3\u03C4\u03B5 \u03B1\u03C0\u03BF \u03B1\u03C1\u03B9\u03B8\u03BC\u03BF\u03CD\u03C2 \u03C3\u03B5\u03BB\u03B9\u03B4\u03CE\u03BD, \u03C7\u03C9\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03B5\u03C2 \u03BC\u03B5 \u03BA\u03CC\u03BC\u03BC\u03B1 \u03AE \u03C3\u03C5\u03BD\u03B1\u03C1\u03C4\u03AE\u03C3\u03B5\u03B9\u03C2 \u03CC\u03C0\u03C9\u03C2 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Go goToPage=Go
true=\u0391\u03BB\u03B7\u03B8\u03AD\u03C2 true=\u0391\u03BB\u03B7\u03B8\u03AD\u03C2
false=\u039B\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF false=\u039B\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF
@@ -19,6 +20,7 @@ save=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7
close=\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF close=\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF
filesSelected=\u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C0\u03BF\u03C5 \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B1\u03BD filesSelected=\u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C0\u03BF\u03C5 \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B1\u03BD
noFavourites=\u039A\u03B1\u03BD\u03AD\u03BD\u03B1 \u03B1\u03B3\u03B1\u03C0\u03AE\u03BC\u03B5\u03BD\u03BF \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF noFavourites=\u039A\u03B1\u03BD\u03AD\u03BD\u03B1 \u03B1\u03B3\u03B1\u03C0\u03AE\u03BC\u03B5\u03BD\u03BF \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF
downloadComplete=Download Complete
bored=\u0392\u03B1\u03C1\u03B9\u03AD\u03C3\u03C4\u03B5 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03BC\u03AD\u03BD\u03B5\u03C4\u03B5; bored=\u0392\u03B1\u03C1\u03B9\u03AD\u03C3\u03C4\u03B5 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03BC\u03AD\u03BD\u03B5\u03C4\u03B5;
alphabet=\u0391\u03BB\u03C6\u03AC\u03B2\u03B7\u03C4\u03BF alphabet=\u0391\u03BB\u03C6\u03AC\u03B2\u03B7\u03C4\u03BF
downloadPdf=\u039A\u03B1\u03C4\u03AD\u03B2\u03B1\u03C3\u03BC\u03B1 \u03C4\u03BF\u03C5 PDF downloadPdf=\u039A\u03B1\u03C4\u03AD\u03B2\u03B1\u03C3\u03BC\u03B1 \u03C4\u03BF\u03C5 PDF
@@ -42,7 +44,7 @@ red=\u039A\u03CC\u03BA\u03BA\u03B9\u03BD\u03BF
green=\u03A0\u03C1\u03AC\u03C3\u03B9\u03BD\u03BF green=\u03A0\u03C1\u03AC\u03C3\u03B9\u03BD\u03BF
blue=\u039C\u03C0\u03BB\u03AD blue=\u039C\u03C0\u03BB\u03AD
custom=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE... custom=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4
userNotFoundMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03B2\u03C1\u03AD\u03B8\u03B7\u03BA\u03B5. userNotFoundMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03B2\u03C1\u03AD\u03B8\u03B7\u03BA\u03B5.
incorrectPasswordMessage=\u039F \u03C4\u03C1\u03AD\u03C7\u03C9\u03BD \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03BB\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2. incorrectPasswordMessage=\u039F \u03C4\u03C1\u03AD\u03C7\u03C9\u03BD \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03BB\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2.
usernameExistsMessage=\u03A4\u03BF \u03BD\u03AD\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C5\u03C0\u03AC\u03C1\u03C7\u03B5\u03B9 \u03AE\u03B4\u03B7. usernameExistsMessage=\u03A4\u03BF \u03BD\u03AD\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C5\u03C0\u03AC\u03C1\u03C7\u03B5\u03B9 \u03AE\u03B4\u03B7.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2
changeCreds.title=\u0391\u03BB\u03BB\u03B1\u03B3\u03AE \u0394\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03B7\u03C1\u03AF\u03C9\u03BD changeCreds.title=\u0391\u03BB\u03BB\u03B1\u03B3\u03AE \u0394\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03B7\u03C1\u03AF\u03C9\u03BD
changeCreds.header=\u0395\u03BD\u03B7\u03BC\u03AD\u03C1\u03C9\u03C3\u03B7 \u03C4\u03C9\u03BD \u03BB\u03B5\u03C0\u03C4\u03BF\u03BC\u03B5\u03C1\u03B5\u03B9\u03CE\u03BD \u03C4\u03BF\u03C5 \u039B\u03BF\u03B3\u03B1\u03C1\u03B9\u03B1\u03C3\u03BC\u03BF\u03CD \u03C3\u03B1\u03C2 changeCreds.header=\u0395\u03BD\u03B7\u03BC\u03AD\u03C1\u03C9\u03C3\u03B7 \u03C4\u03C9\u03BD \u03BB\u03B5\u03C0\u03C4\u03BF\u03BC\u03B5\u03C1\u03B5\u03B9\u03CE\u03BD \u03C4\u03BF\u03C5 \u039B\u03BF\u03B3\u03B1\u03C1\u03B9\u03B1\u03C3\u03BC\u03BF\u03CD \u03C3\u03B1\u03C2
changeCreds.changeUserAndPassword=\u03A7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03B5\u03AF\u03C4\u03B5 \u03C4\u03B1 \u03C0\u03C1\u03BF\u03B5\u03C0\u03B9\u03BB\u03B5\u03B3\u03BC\u03AD\u03BD\u03B1 \u03B4\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03AE\u03C1\u03B9\u03B1 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7\u03C2. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03B9\u03C3\u03AC\u03B3\u03B5\u03C4\u03B5 \u03BD\u03AD\u03BF \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 (\u03BA\u03B1\u03B9 \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03B1\u03BD \u03C4\u03BF \u03B5\u03C0\u03B9\u03B8\u03C5\u03BC\u03B5\u03AF\u03C4\u03B5) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=\u039D\u03AD\u03BF \u038C\u03BD\u03BF\u03BC\u03B1 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7 changeCreds.newUsername=\u039D\u03AD\u03BF \u038C\u03BD\u03BF\u03BC\u03B1 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7
changeCreds.oldPassword=\u03A4\u03C1\u03AD\u03C7\u03C9\u03BD \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 changeCreds.oldPassword=\u03A4\u03C1\u03AD\u03C7\u03C9\u03BD \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
changeCreds.newPassword=\u039D\u03AD\u03BF\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 changeCreds.newPassword=\u039D\u03AD\u03BF\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
@@ -120,7 +124,7 @@ account.accountSettings=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2 \
account.adminSettings=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2 \u0394\u03B9\u03B1\u03C7\u03B5\u03B9\u03C1\u03B9\u03C3\u03C4\u03AE - \u03A0\u03C1\u03BF\u03B2\u03BF\u03BB\u03AE \u03BA\u03B1\u03B9 \u03C0\u03C1\u03BF\u03C3\u03B8\u03AE\u03BA\u03B7 \u03C7\u03C1\u03B7\u03C3\u03C4\u03CE\u03BD account.adminSettings=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2 \u0394\u03B9\u03B1\u03C7\u03B5\u03B9\u03C1\u03B9\u03C3\u03C4\u03AE - \u03A0\u03C1\u03BF\u03B2\u03BF\u03BB\u03AE \u03BA\u03B1\u03B9 \u03C0\u03C1\u03BF\u03C3\u03B8\u03AE\u03BA\u03B7 \u03C7\u03C1\u03B7\u03C3\u03C4\u03CE\u03BD
account.userControlSettings=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2 \u03A7\u03B5\u03B9\u03C1\u03B9\u03C3\u03BC\u03BF\u03CD \u03A7\u03C1\u03B7\u03C3\u03C4\u03CE\u03BD account.userControlSettings=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2 \u03A7\u03B5\u03B9\u03C1\u03B9\u03C3\u03BC\u03BF\u03CD \u03A7\u03C1\u03B7\u03C3\u03C4\u03CE\u03BD
account.changeUsername=\u0391\u03BB\u03BB\u03B1\u03B3\u03AE \u039F\u03BD\u03CC\u03BC\u03B1\u03C4\u03BF\u03C2 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7 account.changeUsername=\u0391\u03BB\u03BB\u03B1\u03B3\u03AE \u039F\u03BD\u03CC\u03BC\u03B1\u03C4\u03BF\u03C2 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7
account.changeUsername=\u0391\u03BB\u03BB\u03B1\u03B3\u03AE \u039F\u03BD\u03CC\u03BC\u03B1\u03C4\u03BF\u03C2 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7 account.newUsername=\u039d\u03ad\u03bf \u038c\u03bd\u03bf\u03bc\u03b1 \u03a7\u03c1\u03ae\u03c3\u03c4\u03b7
account.password=\u0395\u03C0\u03B9\u03B2\u03B5\u03B2\u03B1\u03AF\u03C9\u03C3\u03B7 \u039A\u03C9\u03B4\u03B9\u03BA\u03BF\u03CD \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 account.password=\u0395\u03C0\u03B9\u03B2\u03B5\u03B2\u03B1\u03AF\u03C9\u03C3\u03B7 \u039A\u03C9\u03B4\u03B9\u03BA\u03BF\u03CD \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
account.oldPassword=\u03A0\u03B1\u03BB\u03B9\u03CC\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 account.oldPassword=\u03A0\u03B1\u03BB\u03B9\u03CC\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
account.newPassword=\u039D\u03AD\u03BF\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 account.newPassword=\u039D\u03AD\u03BF\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
@@ -145,8 +149,10 @@ adminUserSettings.roles=\u03A1\u03CC\u03BB\u03BF\u03B9
adminUserSettings.role=\u03A1\u03CC\u03BB\u03BF\u03C2 adminUserSettings.role=\u03A1\u03CC\u03BB\u03BF\u03C2
adminUserSettings.actions=\u0395\u03BD\u03AD\u03C1\u03B3\u03B5\u03B9\u03B5\u03C2 adminUserSettings.actions=\u0395\u03BD\u03AD\u03C1\u03B3\u03B5\u03B9\u03B5\u03C2
adminUserSettings.apiUser=\u03A0\u03B5\u03C1\u03B9\u03BF\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03B4\u03B9\u03B5\u03C0\u03B1\u03C6\u03AE \u03C0\u03C1\u03BF\u03B3\u03C1\u03B1\u03BC\u03BC\u03B1\u03C4\u03B9\u03C3\u03BC\u03BF\u03CD \u03B5\u03C6\u03B1\u03C1\u03BC\u03BF\u03B3\u03CE\u03BD (API User) adminUserSettings.apiUser=\u03A0\u03B5\u03C1\u03B9\u03BF\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03B4\u03B9\u03B5\u03C0\u03B1\u03C6\u03AE \u03C0\u03C1\u03BF\u03B3\u03C1\u03B1\u03BC\u03BC\u03B1\u03C4\u03B9\u03C3\u03BC\u03BF\u03CD \u03B5\u03C6\u03B1\u03C1\u03BC\u03BF\u03B3\u03CE\u03BD (API User)
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=\u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03BC\u03CC\u03BD\u03BF \u0399\u03C3\u03C4\u03BF\u03CD adminUserSettings.webOnlyUser=\u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03BC\u03CC\u03BD\u03BF \u0399\u03C3\u03C4\u03BF\u03CD
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=\u0391\u03BD\u03B1\u03B3\u03BA\u03AC\u03C3\u03C4\u03B5 \u03C4\u03BF\u03BD \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03BD\u03B1 \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9 \u03C4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7/\u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03BA\u03B1\u03C4\u03AC \u03C4\u03B7 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7 adminUserSettings.forceChange=\u0391\u03BD\u03B1\u03B3\u03BA\u03AC\u03C3\u03C4\u03B5 \u03C4\u03BF\u03BD \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03BD\u03B1 \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9 \u03C4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7/\u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03BA\u03B1\u03C4\u03AC \u03C4\u03B7 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7
adminUserSettings.submit=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7 adminUserSettings.submit=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7
@@ -362,11 +368,11 @@ PdfToSinglePage.tags=single page
home.showJS.title=\u0395\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7 Javascript home.showJS.title=\u0395\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7 Javascript
home.showJS.desc=\u0391\u03BD\u03B6\u03AE\u03C4\u03B7\u03C3\u03B7 \u03BA\u03B1\u03B9 \u03B5\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7 \u03BA\u03CE\u03B4\u03B9\u03BA\u03B1 Javascript \u03C0\u03BF\u03C5 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03B5\u03BD\u03C3\u03C9\u03BC\u03B1\u03C4\u03C9\u03BC\u03AD\u03BD\u03BF \u03BC\u03AD\u03C3\u03B1 \u03C3\u03B5 \u03AD\u03BD\u03B1 PDF home.showJS.desc=\u0391\u03BD\u03B6\u03AE\u03C4\u03B7\u03C3\u03B7 \u03BA\u03B1\u03B9 \u03B5\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7 \u03BA\u03CE\u03B4\u03B9\u03BA\u03B1 Javascript \u03C0\u03BF\u03C5 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03B5\u03BD\u03C3\u03C9\u03BC\u03B1\u03C4\u03C9\u03BC\u03AD\u03BD\u03BF \u03BC\u03AD\u03C3\u03B1 \u03C3\u03B5 \u03AD\u03BD\u03B1 PDF
showJS.tags=Redact,Hide,black out,black,marker,hidden showJS.tags=JS
home.autoRedact.title=\u0391\u03C5\u03C4\u03CC\u03BC\u03B1\u03C4\u03BF \u039C\u03B1\u03CD\u03C1\u03B9\u03C3\u03BC\u03B1 \u039A\u03B5\u03B9\u03BC\u03AD\u03BD\u03BF\u03C5 home.autoRedact.title=\u0391\u03C5\u03C4\u03CC\u03BC\u03B1\u03C4\u03BF \u039C\u03B1\u03CD\u03C1\u03B9\u03C3\u03BC\u03B1 \u039A\u03B5\u03B9\u03BC\u03AD\u03BD\u03BF\u03C5
home.autoRedact.desc=\u0391\u03C5\u03C4\u03CC\u03BC\u03B1\u03C4\u03B7 \u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 (\u039C\u03B1\u03CD\u03C1\u03B9\u03C3\u03BC\u03B1) \u03BA\u03B5\u03AF\u03BC\u03B5\u03BD\u03BF\u03C5 \u03C3\u03B5 PDF \u03BC\u03B5 \u03B2\u03AC\u03C3\u03B7 \u03C4\u03BF \u03BA\u03B5\u03AF\u03BC\u03B5\u03BD\u03BF \u03B5\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE\u03C2 home.autoRedact.desc=\u0391\u03C5\u03C4\u03CC\u03BC\u03B1\u03C4\u03B7 \u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 (\u039C\u03B1\u03CD\u03C1\u03B9\u03C3\u03BC\u03B1) \u03BA\u03B5\u03AF\u03BC\u03B5\u03BD\u03BF\u03C5 \u03C3\u03B5 PDF \u03BC\u03B5 \u03B2\u03AC\u03C3\u03B7 \u03C4\u03BF \u03BA\u03B5\u03AF\u03BC\u03B5\u03BD\u03BF \u03B5\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE\u03C2
showJS.tags=Redact,Hide,black out,black,marker,hidden autoRedact.tags=Redact,Hide,black out,black,marker,hidden
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 PDF sanitizePDF.title=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 PDF
sanitizePDF.header=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 \u03B5\u03BD\u03CC\u03C2 PDF \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5 sanitizePDF.header=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 \u03B5\u03BD\u03CC\u03C2 PDF \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5
@@ -621,6 +637,18 @@ compare.document.1=\u0388\u03B3\u03B3\u03C1\u03B1\u03C6\u03BF 1
compare.document.2=\u0388\u03B3\u03B3\u03C1\u03B1\u03C6\u03BF 2 compare.document.2=\u0388\u03B3\u03B3\u03C1\u03B1\u03C6\u03BF 2
compare.submit=\u03A3\u03CD\u03B3\u03BA\u03C1\u03B9\u03C3\u03B7 compare.submit=\u03A3\u03CD\u03B3\u03BA\u03C1\u03B9\u03C3\u03B7
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=\u03A5\u03C0\u03BF\u03B3\u03C1\u03B1\u03C6\u03AE sign.title=\u03A5\u03C0\u03BF\u03B3\u03C1\u03B1\u03C6\u03AE
@@ -866,7 +894,6 @@ changeMetadata.keywords=\u039B\u03AD\u03BE\u03B5\u03B9\u03C2-\u03BA\u03BB\u03B5\
changeMetadata.modDate=\u0397\u03BC\u03B5\u03C1\u03BF\u03BC\u03B7\u03BD\u03AF\u03B1 \u03A4\u03C1\u03BF\u03C0\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7\u03C2 (yyyy/MM/dd HH:mm:ss): changeMetadata.modDate=\u0397\u03BC\u03B5\u03C1\u03BF\u03BC\u03B7\u03BD\u03AF\u03B1 \u03A4\u03C1\u03BF\u03C0\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7\u03C2 (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=\u03A0\u03B1\u03C1\u03B1\u03B3\u03C9\u03B3\u03CC\u03C2: changeMetadata.producer=\u03A0\u03B1\u03C1\u03B1\u03B3\u03C9\u03B3\u03CC\u03C2:
changeMetadata.subject=\u0398\u03AD\u03BC\u03B1: changeMetadata.subject=\u0398\u03AD\u03BC\u03B1:
changeMetadata.title=\u03A4\u03AF\u03C4\u03BB\u03BF\u03C2:
changeMetadata.trapped=Trapped: changeMetadata.trapped=Trapped:
changeMetadata.selectText.4=\u0386\u03BB\u03BB\u03B1 \u03BC\u03B5\u03C4\u03B1\u03B4\u03B5\u03B4\u03BF\u03BC\u03AD\u03BD\u03B1: changeMetadata.selectText.4=\u0386\u03BB\u03BB\u03B1 \u03BC\u03B5\u03C4\u03B1\u03B4\u03B5\u03B4\u03BF\u03BC\u03AD\u03BD\u03B1:
changeMetadata.selectText.5=\u03A0\u03C1\u03BF\u03C3\u03B8\u03AE\u03BA\u03B7 \u03B5\u03B3\u03B3\u03C1\u03B1\u03C6\u03AE\u03C2 \u03C0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03C3\u03BC\u03AD\u03BD\u03C9\u03BD \u03BC\u03B5\u03C4\u03B1\u03B4\u03B5\u03B4\u03BF\u03BC\u03AD\u03BD\u03C9\u03BD changeMetadata.selectText.5=\u03A0\u03C1\u03BF\u03C3\u03B8\u03AE\u03BA\u03B7 \u03B5\u03B3\u03B3\u03C1\u03B1\u03C6\u03AE\u03C2 \u03C0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03C3\u03BC\u03AD\u03BD\u03C9\u03BD \u03BC\u03B5\u03C4\u03B1\u03B4\u03B5\u03B4\u03BF\u03BC\u03AD\u03BD\u03C9\u03BD
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr = left to right, rtl = right to left) # the direction that the language is written (ltr = left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=Select Image(s)
genericSubmit=Submit genericSubmit=Submit
processTimeWarning=Warning: This process can take up to a minute depending on file-size processTimeWarning=Warning: This process can take up to a minute depending on file-size
pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) : pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Go goToPage=Go
true=True true=True
false=False false=False
@@ -19,6 +20,7 @@ save=Save
close=Close close=Close
filesSelected=files selected filesSelected=files selected
noFavourites=No favourites added noFavourites=No favourites added
downloadComplete=Download Complete
bored=Bored Waiting? bored=Bored Waiting?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=Download PDF downloadPdf=Download PDF
@@ -42,7 +44,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -119,8 +123,8 @@ account.title=Account Settings
account.accountSettings=Account Settings account.accountSettings=Account Settings
account.adminSettings=Admin Settings - View and Add Users account.adminSettings=Admin Settings - View and Add Users
account.userControlSettings=User Control Settings account.userControlSettings=User Control Settings
account.changeUsername=New Username
account.changeUsername=Change Username account.changeUsername=Change Username
account.newUsername=New Username
account.password=Confirmation Password account.password=Confirmation Password
account.oldPassword=Old password account.oldPassword=Old password
account.newPassword=New Password account.newPassword=New Password
@@ -145,9 +149,11 @@ adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange = Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
############# #############
@@ -366,7 +372,7 @@ showJS.tags=JS
home.autoRedact.title=Auto Redact home.autoRedact.title=Auto Redact
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
showJS.tags=Redact,Hide,black out,black,marker,hidden autoRedact.tags=Redact,Hide,black out,black,marker,hidden
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=Sanitize PDF sanitizePDF.title=Sanitize PDF
sanitizePDF.header=Sanitize a PDF file sanitizePDF.header=Sanitize a PDF file
@@ -621,6 +637,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Compare compare.submit=Compare
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sign sign.title=Sign
@@ -866,7 +894,6 @@ changeMetadata.keywords=Keywords:
changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss): changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=Producer: changeMetadata.producer=Producer:
changeMetadata.subject=Subject: changeMetadata.subject=Subject:
changeMetadata.title=Title:
changeMetadata.trapped=Trapped: changeMetadata.trapped=Trapped:
changeMetadata.selectText.4=Other Metadata: changeMetadata.selectText.4=Other Metadata:
changeMetadata.selectText.5=Add Custom Metadata Entry changeMetadata.selectText.5=Add Custom Metadata Entry
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=Select Image(s)
genericSubmit=Submit genericSubmit=Submit
processTimeWarning=Warning: This process can take up to a minute depending on file-size processTimeWarning=Warning: This process can take up to a minute depending on file-size
pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) : pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Go goToPage=Go
true=True true=True
false=False false=False
@@ -19,6 +20,7 @@ save=Save
close=Close close=Close
filesSelected=files selected filesSelected=files selected
noFavourites=No favorites added noFavourites=No favorites added
downloadComplete=Download Complete
bored=Bored Waiting? bored=Bored Waiting?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=Download PDF downloadPdf=Download PDF
@@ -42,7 +44,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -120,7 +124,7 @@ account.accountSettings=Account Settings
account.adminSettings=Admin Settings - View and Add Users account.adminSettings=Admin Settings - View and Add Users
account.userControlSettings=User Control Settings account.userControlSettings=User Control Settings
account.changeUsername=Change Username account.changeUsername=Change Username
account.changeUsername=Change Username account.newUsername=New Username
account.password=Confirmation Password account.password=Confirmation Password
account.oldPassword=Old password account.oldPassword=Old password
account.newPassword=New Password account.newPassword=New Password
@@ -145,9 +149,11 @@ adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
############# #############
@@ -366,7 +372,7 @@ showJS.tags=JS
home.autoRedact.title=Auto Redact home.autoRedact.title=Auto Redact
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
showJS.tags=JS autoRedact.tags=Redact,Hide,black out,black,marker,hidden
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=Sanitize PDF sanitizePDF.title=Sanitize PDF
sanitizePDF.header=Sanitize a PDF file sanitizePDF.header=Sanitize a PDF file
@@ -621,6 +637,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Compare compare.submit=Compare
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sign sign.title=Sign
@@ -866,7 +894,6 @@ changeMetadata.keywords=Keywords:
changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss): changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=Producer: changeMetadata.producer=Producer:
changeMetadata.subject=Subject: changeMetadata.subject=Subject:
changeMetadata.title=Title:
changeMetadata.trapped=Trapped: changeMetadata.trapped=Trapped:
changeMetadata.selectText.4=Other Metadata: changeMetadata.selectText.4=Other Metadata:
changeMetadata.selectText.5=Add Custom Metadata Entry changeMetadata.selectText.5=Add Custom Metadata Entry
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=Seleccionar Imagen(es)
genericSubmit=Enviar genericSubmit=Enviar
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma): pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma):
pageSelectionPrompt=Selección de página personalizada (Intruduzca una lista de números de página separados por comas 1,5,6 o funciones como 2n+1) :
goToPage=Ir a goToPage=Ir a
true=Verdadero true=Verdadero
false=Falso false=Falso
@@ -19,6 +20,7 @@ save=Guardar
close=Cerrar close=Cerrar
filesSelected=archivos seleccionados filesSelected=archivos seleccionados
noFavourites=No se agregaron favoritos noFavourites=No se agregaron favoritos
downloadComplete=Download Complete
bored=¿Cansado de esperar? bored=¿Cansado de esperar?
alphabet=Alfabeto alphabet=Alfabeto
downloadPdf=Descargar PDF downloadPdf=Descargar PDF
@@ -42,38 +44,40 @@ red=Rojo
green=Verde green=Verde
blue=Azul blue=Azul
custom=Personalizado... custom=Personalizado...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Tarea en progreso, puede no funcionar o ralentizarse; ¡por favor, informe de cualquier problema!
poweredBy=Powered by poweredBy=Desarrollado por
yes=Yes yes=
no=No no=No
changedCredsMessage=Se cambiaron las credenciales! changedCredsMessage=Se cambiaron las credenciales!
notAuthenticatedMessage=Usuario no autentificado. notAuthenticatedMessage=Usuario no autentificado.
userNotFoundMessage=Usuario no encontrado. userNotFoundMessage=Usuario no encontrado.
incorrectPasswordMessage=La contraseña actual no es correcta. incorrectPasswordMessage=La contraseña actual no es correcta.
usernameExistsMessage=El nuevo nombre de usuario está en uso. usernameExistsMessage=El nuevo nombre de usuario está en uso.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Menú de canalización (Alfa)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Cargar personalización
pipeline.configureButton=Configure pipeline.configureButton=Configurar
pipeline.defaultOption=Custom pipeline.defaultOption=Personalizar
pipeline.submitButton=Submit pipeline.submitButton=Enviar
###################### ######################
# Pipeline Options # # Pipeline Options #
###################### ######################
pipelineOptions.header=Pipeline Configuration pipelineOptions.header=Configuración de la canalización
pipelineOptions.pipelineNameLabel=Pipeline Name pipelineOptions.pipelineNameLabel=Nombre de la canalización
pipelineOptions.saveSettings=Save Operation Settings pipelineOptions.saveSettings=Guardar configuración de la canalización
pipelineOptions.pipelineNamePrompt=Enter pipeline name here pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre de la canalización
pipelineOptions.selectOperation=Select Operation pipelineOptions.selectOperation=Seleccione la operación
pipelineOptions.addOperationButton=Add operation pipelineOptions.addOperationButton=Añadir operación
pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.pipelineHeader=Canalización:
pipelineOptions.saveButton=Download pipelineOptions.saveButton=Descargar
pipelineOptions.validateButton=Validate pipelineOptions.validateButton=Validar
@@ -106,7 +110,7 @@ settings.accountSettings=Configuración de la cuenta
changeCreds.title=Cambiar Credenciales changeCreds.title=Cambiar Credenciales
changeCreds.header=Actualice los detalles de su cuenta 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.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Nuevo usuario changeCreds.newUsername=Nuevo usuario
changeCreds.oldPassword=Contraseña actual changeCreds.oldPassword=Contraseña actual
changeCreds.newPassword=Nueva contraseña changeCreds.newPassword=Nueva contraseña
@@ -120,7 +124,7 @@ account.accountSettings=Configuración de la cuenta
account.adminSettings=Configuración de Administrador - Ver y Añadir Usuarios account.adminSettings=Configuración de Administrador - Ver y Añadir Usuarios
account.userControlSettings=Configuración de control de usuario account.userControlSettings=Configuración de control de usuario
account.changeUsername=Cambiar nombre de usuario account.changeUsername=Cambiar nombre de usuario
account.changeUsername=Cambiar nombre de usuario account.newUsername=nuevo nombre de usuario
account.password=Confirmar contraseña account.password=Confirmar contraseña
account.oldPassword=Contraseña anterior account.oldPassword=Contraseña anterior
account.newPassword=Nueva Contraseña account.newPassword=Nueva Contraseña
@@ -145,8 +149,10 @@ adminUserSettings.roles=Roles
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Acciones adminUserSettings.actions=Acciones
adminUserSettings.apiUser=Usuario limitado de API adminUserSettings.apiUser=Usuario limitado de API
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Usuario solo web adminUserSettings.webOnlyUser=Usuario solo web
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso
adminUserSettings.submit=Guardar Usuario adminUserSettings.submit=Guardar Usuario
@@ -366,7 +372,7 @@ showJS.tags=JS
home.autoRedact.title=Auto Redactar home.autoRedact.title=Auto Redactar
home.autoRedact.desc=Redactar automáticamente (ocultar) texto en un PDF según el texto introducido home.autoRedact.desc=Redactar automáticamente (ocultar) texto en un PDF según el texto introducido
showJS.tags=JS autoRedact.tags=Redact,Hide,black out,black,marker,hidden
home.tableExtraxt.title=PDF a CSV home.tableExtraxt.title=PDF a CSV
home.tableExtraxt.desc=Extraer Tablas de un PDF convirtiéndolas a CSV home.tableExtraxt.desc=Extraer Tablas de un PDF convirtiéndolas a CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -466,37 +481,38 @@ HTMLToPDF.header=HTML a PDF
HTMLToPDF.help=Acepta archivos HTML y ZIPs conteniendo los html/css/imágenes, etc, requeridas HTMLToPDF.help=Acepta archivos HTML y ZIPs conteniendo los html/css/imágenes, etc, requeridas
HTMLToPDF.submit=Convertir HTMLToPDF.submit=Convertir
HTMLToPDF.credit=Utiliza WeasyPrint HTMLToPDF.credit=Utiliza WeasyPrint
HTMLToPDF.zoom=Zoom level for displaying the website. HTMLToPDF.zoom=Nivel de zoom para mostrar la página web.
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default) HTMLToPDF.pageWidth=Ancho de la página en centímetros. (Dejar en blanco por defecto)
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default) HTMLToPDF.pageHeight=Alto de la página en centímetros. (Dejar en blanco por defecto)
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default) HTMLToPDF.marginTop=Margen superior de la página en milímetros. (Dejar en blanco por defecto)
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default) HTMLToPDF.marginBottom=Margen inferior de la página en milímetros. (Dejar en blanco por defecto)
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default) HTMLToPDF.marginLeft=Margen izquierdo de la página en milímetros. (Dejar en blanco por defecto)
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default) HTMLToPDF.marginRight=Margen derecho de la página en milímetros. (Dejar en blanco por defecto)
HTMLToPDF.printBackground=Render the background of websites. HTMLToPDF.printBackground=Renderizar el fondo de las páginas web.
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number) HTMLToPDF.defaultHeader=Habilitar encabezado predeterminado (Nombre y número de página)
HTMLToPDF.cssMediaType=Change the CSS media type of the page. HTMLToPDF.cssMediaType=Cambiar el tipo de medio CSS de la página.
HTMLToPDF.none=None HTMLToPDF.none=Ninguno
HTMLToPDF.print=Print HTMLToPDF.print=Imprimir
HTMLToPDF.screen=Screen HTMLToPDF.screen=Pantalla
#AddStampRequest #AddStampRequest
AddStampRequest.header=Stamp PDF AddStampRequest.header=Sellar PDF
AddStampRequest.title=Stamp PDF AddStampRequest.title=Sellar PDF
AddStampRequest.stampType=Stamp Type AddStampRequest.stampType=Tipo de sello
AddStampRequest.stampText=Stamp Text AddStampRequest.stampText=Texto del sello
AddStampRequest.stampImage=Stamp Image AddStampRequest.stampImage=Imagen de sello
AddStampRequest.alphabet=Alphabet AddStampRequest.alphabet=Alfabeto
AddStampRequest.fontSize=Font/Image Size AddStampRequest.fontSize=Tamaño de fuente/imagen
AddStampRequest.rotation=Rotation AddStampRequest.rotation=Rotación
AddStampRequest.opacity=Opacity AddStampRequest.opacity=Opacidad
AddStampRequest.position=Position AddStampRequest.position=Posición
AddStampRequest.overrideX=Override X Coordinate AddStampRequest.overrideX=Forzar coordenada X
AddStampRequest.overrideY=Override Y Coordinate AddStampRequest.overrideY=Forzar coordenada Y
AddStampRequest.customMargin=Custom Margin AddStampRequest.customMargin=Personalizar margen
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Personalizar color de texto
AddStampRequest.submit=Submit AddStampRequest.submit=Enviar
#sanitizePDF #sanitizePDF
sanitizePDF.title=Desinfectar archivo PDF sanitizePDF.title=Desinfectar archivo PDF
@@ -561,7 +577,7 @@ autoSplitPDF.submit=Entregar
#pipeline #pipeline
pipeline.title=Pipeline pipeline.title=Canalización
#pageLayout #pageLayout
@@ -584,11 +600,11 @@ scalePages.submit=Entregar
certSign.title=Firma con certificado certSign.title=Firma con certificado
certSign.header=Firmar un PDF con su certificado (en desarrollo) certSign.header=Firmar un PDF con su certificado (en desarrollo)
certSign.selectPDF=Seleccione un archivo PDF para firmar: certSign.selectPDF=Seleccione un archivo PDF para firmar:
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below. certSign.jksNote=Nota: si el tipo de certificado no está enla lista de abajo, por favor conviértalo a un archivo almacén de claves de Java Java KeyStore (.jks) utilizando la herramienta línea de comandos. Posteriormente, seleccione en el listado de abajo la opción archivo .jks.
certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der): certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der):
certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der): certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der):
certSign.selectP12=Seleccione su archivo de almacén de claves PKCS#12 (.p12 o .pfx) (Opcional, si se proporciona, debe contener su clave privada y certificado): certSign.selectP12=Seleccione su archivo de almacén de claves PKCS#12 (.p12 o .pfx) (Opcional, si se proporciona, debe contener su clave privada y certificado):
certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore): certSign.selectJKS=Seleccione su archivo de almacén de claves Java KeyStore (.jks or .keystore):
certSign.certType=Tipo de certificado certSign.certType=Tipo de certificado
certSign.password=Introduzca su almacén de claves o contraseña de clave privada (si corresponde): certSign.password=Introduzca su almacén de claves o contraseña de clave privada (si corresponde):
certSign.showSig=Mostrar firma certSign.showSig=Mostrar firma
@@ -621,6 +637,18 @@ compare.document.1=Documento 1
compare.document.2=Documento 2 compare.document.2=Documento 2
compare.submit=Comparar compare.submit=Comparar
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Firmar sign.title=Firmar
@@ -866,7 +894,6 @@ changeMetadata.keywords=Palabras clave:
changeMetadata.modDate=Fecha de modificación (aaaa/MM/dd HH:mm:ss): changeMetadata.modDate=Fecha de modificación (aaaa/MM/dd HH:mm:ss):
changeMetadata.producer=Productor: changeMetadata.producer=Productor:
changeMetadata.subject=Asunto: changeMetadata.subject=Asunto:
changeMetadata.title=Título:
changeMetadata.trapped=Capturado: changeMetadata.trapped=Capturado:
changeMetadata.selectText.4=Otros Metadatos: changeMetadata.selectText.4=Otros Metadatos:
changeMetadata.selectText.5=Agregar entrada de metadatos personalizados changeMetadata.selectText.5=Agregar entrada de metadatos personalizados
@@ -958,14 +985,14 @@ split-by-sections.vertical.label=Divisiones Verticales
split-by-sections.horizontal.placeholder=Introduzca el número de divisiones horizontales split-by-sections.horizontal.placeholder=Introduzca el número de divisiones horizontales
split-by-sections.vertical.placeholder=Introduzca el número de divisiones verticales split-by-sections.vertical.placeholder=Introduzca el número de divisiones verticales
split-by-sections.submit=Dividir PDF split-by-sections.submit=Dividir PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licencias
licenses.title=3rd Party Licenses licenses.title=Licencias de terceros
licenses.header=3rd Party Licenses licenses.header=Licencias de terceros
licenses.module=Module licenses.module=Módulo
licenses.version=Version licenses.version=Versión
licenses.license=License licenses.license=Licencia

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=Hautatu Irudia(k)
genericSubmit=Bidali genericSubmit=Bidali
processTimeWarning=Oharra: prozesu honetarako minutu bat ere beharko da fitxategiaren tamaiaren arabera processTimeWarning=Oharra: prozesu honetarako minutu bat ere beharko da fitxategiaren tamaiaren arabera
pageOrderPrompt=Orrialdeen ordena (sartu komaz bereizitako orrialde-zenbakien zerrenda) pageOrderPrompt=Orrialdeen ordena (sartu komaz bereizitako orrialde-zenbakien zerrenda)
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Joan goToPage=Joan
true=Egiazkoa true=Egiazkoa
false=Faltsua false=Faltsua
@@ -19,6 +20,7 @@ save=Gorde
close=Itxi close=Itxi
filesSelected=Hautatutako fitxategiak filesSelected=Hautatutako fitxategiak
noFavourites=Ez dira gogokoak gehitu noFavourites=Ez dira gogokoak gehitu
downloadComplete=Download Complete
bored=Itxaroten aspertuta? bored=Itxaroten aspertuta?
alphabet=Alfabetoa alphabet=Alfabetoa
downloadPdf=PDFa deskargatu downloadPdf=PDFa deskargatu
@@ -42,7 +44,7 @@ red=Gorria
green=Berdea green=Berdea
blue=Urdina blue=Urdina
custom=Pertsonalizatu... custom=Pertsonalizatu...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=Kontuaren ezarpenak
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -120,7 +124,7 @@ account.accountSettings=Kontuaren ezarpenak
account.adminSettings=Admin ezarpenak - Ikusi eta gehitu Erabiltzaileak account.adminSettings=Admin ezarpenak - Ikusi eta gehitu Erabiltzaileak
account.userControlSettings=Erabiltzaile ezarpen kontrolak account.userControlSettings=Erabiltzaile ezarpen kontrolak
account.changeUsername=Aldatu erabiltzaile izena account.changeUsername=Aldatu erabiltzaile izena
account.changeUsername=Aldatu erabiltzaile izena account.newUsername=Erabiltzaile izen berria
account.password=Konfirmatu pasahitza account.password=Konfirmatu pasahitza
account.oldPassword=Pasahitz zaharra account.oldPassword=Pasahitz zaharra
account.newPassword=Pasahitz berria account.newPassword=Pasahitz berria
@@ -145,9 +149,11 @@ adminUserSettings.roles=Rolak
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Ekintzak adminUserSettings.actions=Ekintzak
adminUserSettings.apiUser=APIren erabiltzaile mugatua adminUserSettings.apiUser=APIren erabiltzaile mugatua
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web-erabiltzailea bakarrik adminUserSettings.webOnlyUser=Web-erabiltzailea bakarrik
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Gorde Erabiltzailea adminUserSettings.submit=Gorde Erabiltzailea
############# #############
@@ -366,7 +372,7 @@ showJS.tags=JS
home.autoRedact.title=Auto Idatzi home.autoRedact.title=Auto Idatzi
home.autoRedact.desc=Auto Idatzi testua pdf fitxategian sarrerako testuan oinarritua home.autoRedact.desc=Auto Idatzi testua pdf fitxategian sarrerako testuan oinarritua
showJS.tags=JS autoRedact.tags=Redact,Hide,black out,black,marker,hidden
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=PDF-a desinfektatu sanitizePDF.title=PDF-a desinfektatu
sanitizePDF.header=PDF fitxategi bat desinfektatu sanitizePDF.header=PDF fitxategi bat desinfektatu
@@ -621,6 +637,18 @@ compare.document.1=1. dokumentua
compare.document.2=2. dokumentua compare.document.2=2. dokumentua
compare.submit=Konparatu compare.submit=Konparatu
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sinatu sign.title=Sinatu
@@ -866,7 +894,6 @@ changeMetadata.keywords=Gako-hitzak:
changeMetadata.modDate=Aldatze-data (aaaa/MM/dd HH:mm:ss): changeMetadata.modDate=Aldatze-data (aaaa/MM/dd HH:mm:ss):
changeMetadata.producer=Ekoizlea: changeMetadata.producer=Ekoizlea:
changeMetadata.subject=Gaia: changeMetadata.subject=Gaia:
changeMetadata.title=Izenburua:
changeMetadata.trapped=Trapped: changeMetadata.trapped=Trapped:
changeMetadata.selectText.4=Beste metadatu batzuk: changeMetadata.selectText.4=Beste metadatu batzuk:
changeMetadata.selectText.5=Gehitu metadatu pertsonalizatuen sarrera changeMetadata.selectText.5=Gehitu metadatu pertsonalizatuen sarrera
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=Choisir une image
genericSubmit=Envoyer genericSubmit=Envoyer
processTimeWarning=Attention, ce processus peut prendre jusqu\u2019à une minute en fonction de la taille du fichier. processTimeWarning=Attention, ce processus peut prendre jusqu\u2019à une minute en fonction de la taille du fichier.
pageOrderPrompt=Ordre des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0: pageOrderPrompt=Ordre des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0:
pageSelectionPrompt=Sélection des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0:
goToPage=Aller goToPage=Aller
true=Vrai true=Vrai
false=Faux false=Faux
@@ -19,6 +20,7 @@ save=Enregistrer
close=Fermer close=Fermer
filesSelected=fichiers sélectionnés filesSelected=fichiers sélectionnés
noFavourites=Aucun favori ajouté noFavourites=Aucun favori ajouté
downloadComplete=Téléchargement terminé
bored=Ennuyé d\u2019attendre\u00a0? bored=Ennuyé d\u2019attendre\u00a0?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=Télécharger le PDF downloadPdf=Télécharger le PDF
@@ -42,38 +44,40 @@ red=Rouge
green=Vert green=Vert
blue=Bleu blue=Bleu
custom=Personnalisé\u2026 custom=Personnalisé\u2026
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=En cours de développement, merci de nous remonter les problèmes que vous pourriez constater!
poweredBy=Powered by poweredBy=Propulsé par
yes=Yes yes=Oui
no=No no=Non
changedCredsMessage=Les identifiants ont été mis à jour\u00a0! changedCredsMessage=Les identifiants ont été mis à jour\u00a0!
notAuthenticatedMessage=Utilisateur non authentifié. notAuthenticatedMessage=Utilisateur non authentifié.
userNotFoundMessage=Utilisateur non trouvé. userNotFoundMessage=Utilisateur non trouvé.
incorrectPasswordMessage=Le mot de passe actuel est incorrect. incorrectPasswordMessage=Le mot de passe actuel est incorrect.
usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà. usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Menu Pipeline (Alpha)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Télécharger une personnalisation
pipeline.configureButton=Configure pipeline.configureButton=Configurer
pipeline.defaultOption=Custom pipeline.defaultOption=Personnaliser
pipeline.submitButton=Submit pipeline.submitButton=Soumettre
###################### ######################
# Pipeline Options # # Pipeline Options #
###################### ######################
pipelineOptions.header=Pipeline Configuration pipelineOptions.header=Configuration du pipeline
pipelineOptions.pipelineNameLabel=Pipeline Name pipelineOptions.pipelineNameLabel=Nom du pipeline
pipelineOptions.saveSettings=Save Operation Settings pipelineOptions.saveSettings=Sauvegarder la configuration
pipelineOptions.pipelineNamePrompt=Enter pipeline name here pipelineOptions.pipelineNamePrompt=Entrez ici le nom du pipeline
pipelineOptions.selectOperation=Select Operation pipelineOptions.selectOperation=Sélectionner une opération
pipelineOptions.addOperationButton=Add operation pipelineOptions.addOperationButton=Ajouter une opération
pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download pipelineOptions.saveButton=Télécharger
pipelineOptions.validateButton=Validate pipelineOptions.validateButton=Valider
@@ -106,7 +110,7 @@ settings.accountSettings=Paramètres du compte
changeCreds.title=Modifiez vos identifiants changeCreds.title=Modifiez vos identifiants
changeCreds.header=Mettez à jour vos identifiants de connexion changeCreds.header=Mettez à jour vos identifiants de connexion
changeCreds.changeUserAndPassword=Vous utilisez les identifiants de connexion par défaut. Veuillez entrer un nouveau mot de passe (et nom d\u2019utilisateur si vous le souhaitez) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Nouveau nom d\u2019utilisateur changeCreds.newUsername=Nouveau nom d\u2019utilisateur
changeCreds.oldPassword=Mot de passe actuel changeCreds.oldPassword=Mot de passe actuel
changeCreds.newPassword=Nouveau mot de passe changeCreds.newPassword=Nouveau mot de passe
@@ -120,7 +124,7 @@ account.accountSettings=Paramètres du compte
account.adminSettings=Paramètres d\u2019administration \u2013 Voir et ajouter des utilisateurs account.adminSettings=Paramètres d\u2019administration \u2013 Voir et ajouter des utilisateurs
account.userControlSettings=Contrôle des paramètres des utilisateurs account.userControlSettings=Contrôle des paramètres des utilisateurs
account.changeUsername=Modifier le nom d\u2019utilisateur account.changeUsername=Modifier le nom d\u2019utilisateur
account.changeUsername=Modifier le nom d\u2019utilisateur account.newUsername=Nouveau nom d\u2019utilisateur
account.password=Mot de passe de confirmation account.password=Mot de passe de confirmation
account.oldPassword=Ancien mot de passe account.oldPassword=Ancien mot de passe
account.newPassword=Nouveau mot de passe account.newPassword=Nouveau mot de passe
@@ -145,8 +149,10 @@ adminUserSettings.roles=Rôles
adminUserSettings.role=Rôle adminUserSettings.role=Rôle
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Utilisateur API limité adminUserSettings.apiUser=Utilisateur API limité
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Utilisateur Web uniquement adminUserSettings.webOnlyUser=Utilisateur Web uniquement
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (Paramètres par défaut)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Forcer l\u2019utilisateur à changer son nom d\u2019utilisateur/mot de passe lors de la connexion adminUserSettings.forceChange=Forcer l\u2019utilisateur à changer son nom d\u2019utilisateur/mot de passe lors de la connexion
adminUserSettings.submit=Ajouter adminUserSettings.submit=Ajouter
@@ -158,7 +164,7 @@ home.searchBar=Rechercher des fonctionnalités...
home.viewPdf.title=Visionner le PDF home.viewPdf.title=Visionner le PDF
home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images.
viewPdf.tags=visualiser,lire,annoter,texte,image viewPdf.tags=visualiser,lire,annoter,texte,image
home.multiTool.title=Outil multifonction PDF home.multiTool.title=Outil multifonction PDF
@@ -167,7 +173,7 @@ multiTool.tags=outil multifonction,opération multifonction,interface utilisateu
home.merge.title=Fusionner home.merge.title=Fusionner
home.merge.desc=Fusionnez facilement plusieurs PDF en un seul. home.merge.desc=Fusionnez facilement plusieurs PDF en un seul.
merge.tags=fusionner,opérations sur les pages,backeend,server side,merge merge.tags=fusionner,opérations sur les pages,backend,server side,merge
home.split.title=Diviser home.split.title=Diviser
home.split.desc=Divisez un PDF en plusieurs documents. home.split.desc=Divisez un PDF en plusieurs documents.
@@ -283,9 +289,9 @@ home.removeBlanks.title=Supprimer les pages vierges
home.removeBlanks.desc=Détectez et supprimez les pages vierges d\u2019un PDF. home.removeBlanks.desc=Détectez et supprimez les pages vierges d\u2019un PDF.
removeBlanks.tags=pages vierges,supprimer,nettoyer,cleanup,streamline,non-content,organize removeBlanks.tags=pages vierges,supprimer,nettoyer,cleanup,streamline,non-content,organize
home.removeAnnotations.title=Remove Annotations home.removeAnnotations.title=Supprimer les annotations
home.removeAnnotations.desc=Removes all comments/annotations from a PDF home.removeAnnotations.desc=Supprimer tous les commentaires/annotations d\u2019un PDF.
removeAnnotations.tags=comments,highlight,notes,markup,remove removeAnnotations.tags=commentaires,supprimer,annotations,highlight,notes,markup,remove
home.compare.title=Comparer home.compare.title=Comparer
home.compare.desc=Comparez et visualisez les différences entre deux PDF. home.compare.desc=Comparez et visualisez les différences entre deux PDF.
@@ -362,14 +368,14 @@ PdfToSinglePage.tags=fusionner,merge,une seule page,single page
home.showJS.title=Afficher le JavaScript home.showJS.title=Afficher le JavaScript
home.showJS.desc=Recherche et affiche tout JavaScript injecté dans un PDF. home.showJS.desc=Recherche et affiche tout JavaScript injecté dans un PDF.
showJS.tags=caviarder,redact,auto showJS.tags=JS
home.autoRedact.title=Caviarder automatiquement home.autoRedact.title=Caviarder automatiquement
home.autoRedact.desc=Caviardez automatiquement les informations sensibles d\u2019un PDF. home.autoRedact.desc=Caviardez automatiquement les informations sensibles d\u2019un PDF.
showJS.tags=caviarder,redact,auto autoRedact.tags=caviarder,redact,auto
home.tableExtraxt.title=PDF en CSV home.tableExtraxt.title=PDF en CSV
home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV.
tableExtraxt.tags=CSV,Table Extraction,extract,convert tableExtraxt.tags=CSV,Table Extraction,extract,convert
@@ -379,16 +385,25 @@ autoSizeSplitPDF.tags=pdf,split,document,organization
home.overlay-pdfs.title=Incrustation de PDF home.overlay-pdfs.title=Incrustation de PDF
home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF.
overlay-pdfs.tags=Overlay overlay-pdfs.tags=Overlay,incrustation
home.split-by-sections.title=Split PDF by Sections home.split-by-sections.title=Séparer un PDF en sections
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections home.split-by-sections.desc=Diviser chaque page d\u2019un PDF en sections horizontales/verticales plus petites.
split-by-sections.tags=Section Split, Divide, Customize split-by-sections.tags=Sections,Diviser,Section Split, Divide, Customize
home.AddStampRequest.title=Add Stamp to PDF home.AddStampRequest.title=Ajouter un tampon sur un PDF
home.AddStampRequest.desc=Add text or add image stamps at set locations home.AddStampRequest.desc=Ajouter un texte ou l\u2019image d\u2019un tampon à un emplacement défini.
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Tampon,Ajouter,Stamp,Add image,center image,Watermark,PDF,Embed,Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
@@ -466,37 +481,38 @@ HTMLToPDF.header=HTML en PDF
HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis). HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis).
HTMLToPDF.submit=Convertir HTMLToPDF.submit=Convertir
HTMLToPDF.credit=Utilise WeasyPrint. HTMLToPDF.credit=Utilise WeasyPrint.
HTMLToPDF.zoom=Zoom level for displaying the website. HTMLToPDF.zoom=Niveau de zoom pour l\u2019affichage du site web.
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default) HTMLToPDF.pageWidth=Largeur de la page en centimètres. (Vide par défaut)
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default) HTMLToPDF.pageHeight=Hauteur de la page en centimètres. (Vide par défaut)
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default) HTMLToPDF.marginTop=Marge supérieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default) HTMLToPDF.marginBottom=Marge inférieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default) HTMLToPDF.marginLeft=Marge gauche de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default) HTMLToPDF.marginRight=Marge droite de la page en millimètres. (Vide par défaut)
HTMLToPDF.printBackground=Render the background of websites. HTMLToPDF.printBackground=Restituer l\u2019image de fond des sites web.
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number) HTMLToPDF.defaultHeader=Activer l\u2019entête par défaut (Nom et numéro de page)
HTMLToPDF.cssMediaType=Change the CSS media type of the page. HTMLToPDF.cssMediaType=Modifier le type de média CSS de la page.
HTMLToPDF.none=None HTMLToPDF.none=Aucun
HTMLToPDF.print=Print HTMLToPDF.print=Imprimer
HTMLToPDF.screen=Screen HTMLToPDF.screen=Écran
#AddStampRequest #AddStampRequest
AddStampRequest.header=Stamp PDF AddStampRequest.header=Tampon PDF
AddStampRequest.title=Stamp PDF AddStampRequest.title=Tampon PDF
AddStampRequest.stampType=Stamp Type AddStampRequest.stampType=Type de tampon
AddStampRequest.stampText=Stamp Text AddStampRequest.stampText=Tampon texte
AddStampRequest.stampImage=Stamp Image AddStampRequest.stampImage=Tampon image
AddStampRequest.alphabet=Alphabet AddStampRequest.alphabet=Alphabet
AddStampRequest.fontSize=Font/Image Size AddStampRequest.fontSize=Taille de fonte/image
AddStampRequest.rotation=Rotation AddStampRequest.rotation=Rotation
AddStampRequest.opacity=Opacity AddStampRequest.opacity=Opacité
AddStampRequest.position=Position AddStampRequest.position=Position
AddStampRequest.overrideX=Override X Coordinate AddStampRequest.overrideX=Définir coordonnées X
AddStampRequest.overrideY=Override Y Coordinate AddStampRequest.overrideY=Définir coordonnées Y
AddStampRequest.customMargin=Custom Margin AddStampRequest.customMargin=Marge personnalisée
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Couleur de texte personnalisée
AddStampRequest.submit=Submit AddStampRequest.submit=Soumettre
#sanitizePDF #sanitizePDF
sanitizePDF.title=Assainir sanitizePDF.title=Assainir
@@ -584,11 +600,11 @@ scalePages.submit=Ajuster
certSign.title=Signer avec un certificat certSign.title=Signer avec un certificat
certSign.header=Signer avec un certificat (Travail en cours) certSign.header=Signer avec un certificat (Travail en cours)
certSign.selectPDF=PDF à signer certSign.selectPDF=PDF à signer
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below. certSign.jksNote=Note: Si votre type de certificat n\u2019est pas listé ci\u002Ddessous, merci de le convertir en fichier Java Keystore (.jks) en utilisant l\u2019outil en ligne de commande keytool. Puis choisissez l\u2019option Fichier .jks ci\u002Ddessous.
certSign.selectKey=Fichier de clé privée (format PKCS#8, peut être .pem ou .der) certSign.selectKey=Fichier de clé privée (format PKCS#8, peut être .pem ou .der)
certSign.selectCert=Fichier de certificat (format X.509, peut être .pem ou .der) certSign.selectCert=Fichier de certificat (format X.509, peut être .pem ou .der)
certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, s\u2019il n\u2019est fourni, il doit contenir votre clé privée et votre certificat) certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, s\u2019il n\u2019est fourni, il doit contenir votre clé privée et votre certificat)
certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore): certSign.selectJKS=Sélectionner votre fichier Java Keystore File (.jks or .keystore):
certSign.certType=Type de certificat certSign.certType=Type de certificat
certSign.password=Mot de passe keystore ou clé privée le cas échéant certSign.password=Mot de passe keystore ou clé privée le cas échéant
certSign.showSig=Afficher la signature certSign.showSig=Afficher la signature
@@ -609,9 +625,9 @@ removeBlanks.submit=Supprimer les pages vierges
#removeAnnotations #removeAnnotations
removeAnnotations.title=Remove Annotations removeAnnotations.title=Supprimer les annotations
removeAnnotations.header=Remove Annotations removeAnnotations.header=Supprimer les annotations
removeAnnotations.submit=Remove removeAnnotations.submit=Supprimer
#compare #compare
@@ -621,6 +637,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Comparer compare.submit=Comparer
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Signer sign.title=Signer
@@ -693,14 +721,14 @@ fileToPDF.submit=Convertir
#compress #compress
compress.title=Compresser compress.title=Compresser un PDF
compress.header=Compresser compress.header=Compresser un PDF (lorsque c\u2019est possible!)
compress.credit=Ce service utilise Ghostscript pour la compression et l\u2019optimisation des PDF. compress.credit=Ce service utilise Ghostscript pour la compression et l\u2019optimisation des PDF.
compress.selectText.1=Mode manuel \u2013 de 1 à 4 compress.selectText.1=Mode manuel \u2013 de 1 à 4
compress.selectText.2=Niveau d\u2019optimisation compress.selectText.2=Niveau d\u2019optimisation
compress.selectText.3=4 (terrible pour les images textuelles) compress.selectText.3=4 (terrible pour les images textuelles)
compress.selectText.4=Mode automatique \u2013 ajuste automatiquement la qualité pour obtenir le PDF à la taille exacte compress.selectText.4=Mode automatique \u2013 ajuste automatiquement la qualité pour obtenir le PDF à la taille exacte
compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMo, 10,8\u202fMo, 25\u202fKo) compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMB, 10,8\u202fMB, 25\u202fKB)
compress.submit=Compresser compress.submit=Compresser
@@ -731,8 +759,8 @@ multiTool.title=Outil multifonction PDF
multiTool.header=Outil multifonction PDF multiTool.header=Outil multifonction PDF
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=Visualiser un PDF
viewPdf.header=View PDF viewPdf.header=Visualiser un PDF
#pageRemover #pageRemover
pageRemover.title=Supprimer des pages pageRemover.title=Supprimer des pages
@@ -787,7 +815,7 @@ pdfToImage.multi=Plusieurs images
pdfToImage.colorType=Type d\u2019impression pdfToImage.colorType=Type d\u2019impression
pdfToImage.color=Couleur pdfToImage.color=Couleur
pdfToImage.grey=Niveaux de gris pdfToImage.grey=Niveaux de gris
pdfToImage.blackwhite=Noir et blanc (peut engendre une perde de données\u00a0!) pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données\u00a0!)
pdfToImage.submit=Convertir pdfToImage.submit=Convertir
@@ -866,8 +894,7 @@ changeMetadata.keywords=Mots clés
changeMetadata.modDate=Date de modification (yyyy/MM/dd HH:mm:ss) changeMetadata.modDate=Date de modification (yyyy/MM/dd HH:mm:ss)
changeMetadata.producer=Producteur changeMetadata.producer=Producteur
changeMetadata.subject=Sujet changeMetadata.subject=Sujet
changeMetadata.title=Titre changeMetadata.trapped=Recouvrement (technique dimpression)
changeMetadata.trapped=Défoncé (technique dimpression)
changeMetadata.selectText.4=Autres métadonnées changeMetadata.selectText.4=Autres métadonnées
changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisée changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisée
changeMetadata.submit=Modifier changeMetadata.submit=Modifier
@@ -935,19 +962,19 @@ split-by-size-or-count.submit=Séparer
#overlay-pdfs #overlay-pdfs
overlay-pdfs.header=Overlay PDF Files overlay-pdfs.header=Incrustation de PDF
overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base
overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer
overlay-pdfs.mode.label=Select Overlay Mode overlay-pdfs.mode.label=Sélectionner le mode d\u2019incrustation
overlay-pdfs.mode.sequential=Sequential Overlay overlay-pdfs.mode.sequential=Superposition séquentielle
overlay-pdfs.mode.interleaved=Interleaved Overlay overlay-pdfs.mode.interleaved=Superposition entrelacée
overlay-pdfs.mode.fixedRepeat=Superposition à répétition fixe overlay-pdfs.mode.fixedRepeat=Superposition à répétition fixe
overlay-pdfs.counts.label=Nombre de superpositions (pour le mode de répétition fixe) overlay-pdfs.counts.label=Nombre de superpositions (pour le mode de répétition fixe)
overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1) overlay-pdfs.counts.placeholder=Compteurs (séparés par des virgules, exemple : 2,3,1)
overlay-pdfs.position.label=Select Overlay Position overlay-pdfs.position.label=Définir la position de l\u2019incrustation
overlay-pdfs.position.foreground=Premier plan overlay-pdfs.position.foreground=Premier plan
overlay-pdfs.position.background=Arrière-plan overlay-pdfs.position.background=Arrière-plan
overlay-pdfs.submit=Submit overlay-pdfs.submit=Soumettre
#split-by-sections #split-by-sections
@@ -958,14 +985,14 @@ split-by-sections.vertical.label=Divisions verticales
split-by-sections.horizontal.placeholder=Saisir le nombre de divisions horizontales split-by-sections.horizontal.placeholder=Saisir le nombre de divisions horizontales
split-by-sections.vertical.placeholder=Entrer le nombre de divisions verticales split-by-sections.vertical.placeholder=Entrer le nombre de divisions verticales
split-by-sections.submit=Diviser le PDF split-by-sections.submit=Diviser le PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licences
licenses.title=3rd Party Licenses licenses.title=Licences tierces
licenses.header=3rd Party Licenses licenses.header=Licences tierces
licenses.module=Module licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=Licence

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,6 +11,7 @@ imgPrompt=छवियों का चयन करें
genericSubmit=प्रस्तुत करें genericSubmit=प्रस्तुत करें
processTimeWarning=चेतावनी: यह प्रक्रिया फ़ाइल के आकार पर निर्भर करती है और यह से एक मिनट तक लग सकती है processTimeWarning=चेतावनी: यह प्रक्रिया फ़ाइल के आकार पर निर्भर करती है और यह से एक मिनट तक लग सकती है
pageOrderPrompt=कस्टम पेज क्रम (पेज नंबरों या 2n+1 जैसे कार्यों की एक कॉमा से अलग-अलग सूची दर्ज करें): pageOrderPrompt=कस्टम पेज क्रम (पेज नंबरों या 2n+1 जैसे कार्यों की एक कॉमा से अलग-अलग सूची दर्ज करें):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=जाएँ goToPage=जाएँ
true=सही true=सही
false=गलत false=गलत
@@ -19,6 +20,7 @@ save=सहेजें
close=बंद करें close=बंद करें
filesSelected=फ़ाइलें चयनित हैं filesSelected=फ़ाइलें चयनित हैं
noFavourites=कोई पसंदीदा जोड़ा नहीं गया है noFavourites=कोई पसंदीदा जोड़ा नहीं गया है
downloadComplete=Download Complete
bored=बोर हो रहे हैं? bored=बोर हो रहे हैं?
alphabet=वर्णमाला alphabet=वर्णमाला
downloadPdf=पीडीएफ़ डाउनलोड करें downloadPdf=पीडीएफ़ डाउनलोड करें
@@ -42,7 +44,7 @@ red=लाल
green=हरा green=हरा
blue=नीला blue=नीला
custom=कस्टम... custom=कस्टम...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=Yes
no=No no=No
@@ -51,6 +53,8 @@ notAuthenticatedMessage=उपयोगकर्ता प्रमाणित
userNotFoundMessage=उपयोगकर्ता नहीं मिला। userNotFoundMessage=उपयोगकर्ता नहीं मिला।
incorrectPasswordMessage=वर्तमान पासवर्ड गलत है। incorrectPasswordMessage=वर्तमान पासवर्ड गलत है।
usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है। usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है।
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +110,7 @@ settings.accountSettings=खाता सेटिंग्स
changeCreds.title=क्रेडेंशियल बदलें changeCreds.title=क्रेडेंशियल बदलें
changeCreds.header=अपना खाता विवरण अपडेट करें changeCreds.header=अपना खाता विवरण अपडेट करें
changeCreds.changeUserAndPassword=आप डिफ़ॉल्ट लॉगिन क्रेडेंशियल का उपयोग कर रहे हैं। कृपया एक नया पासवर्ड दर्ज करें (और यदि चाहें तो उपयोगकर्ता नाम) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=नया उपयोगकर्ता नाम changeCreds.newUsername=नया उपयोगकर्ता नाम
changeCreds.oldPassword=वर्तमान पासवर्ड changeCreds.oldPassword=वर्तमान पासवर्ड
changeCreds.newPassword=नया पासवर्ड changeCreds.newPassword=नया पासवर्ड
@@ -120,7 +124,7 @@ account.accountSettings=खाता सेटिंग्स
account.adminSettings=व्यवस्थापक सेटिंग्स - उपयोगकर्ताओं को देखें और जोड़ें account.adminSettings=व्यवस्थापक सेटिंग्स - उपयोगकर्ताओं को देखें और जोड़ें
account.userControlSettings=उपयोगकर्ता नियंत्रण सेटिंग्स account.userControlSettings=उपयोगकर्ता नियंत्रण सेटिंग्स
account.changeUsername=उपयोगकर्ता नाम परिवर्तन करें account.changeUsername=उपयोगकर्ता नाम परिवर्तन करें
account.changeUsername=उपयोगकर्ता नाम परिवर्तन करें account.newUsername=नया उपयोगकर्ता नाम
account.password=पासवर्ड पुष्टि account.password=पासवर्ड पुष्टि
account.oldPassword=पुराना पासवर्ड account.oldPassword=पुराना पासवर्ड
account.newPassword=नया पासवर्ड account.newPassword=नया पासवर्ड
@@ -145,8 +149,10 @@ adminUserSettings.roles=रोल्स
adminUserSettings.role=रोल adminUserSettings.role=रोल
adminUserSettings.actions=क्रियाएँ adminUserSettings.actions=क्रियाएँ
adminUserSettings.apiUser=सीमित API उपयोगकर्ता adminUserSettings.apiUser=सीमित API उपयोगकर्ता
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=केवल वेब उपयोगकर्ता adminUserSettings.webOnlyUser=केवल वेब उपयोगकर्ता
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=उपयोगकर्ता को लॉगिन पर उपयोगकर्ता नाम/पासवर्ड बदलने के लिए मजबूर करें adminUserSettings.forceChange=उपयोगकर्ता को लॉगिन पर उपयोगकर्ता नाम/पासवर्ड बदलने के लिए मजबूर करें
adminUserSettings.submit=उपयोगकर्ता को सहेजें adminUserSettings.submit=उपयोगकर्ता को सहेजें
@@ -362,11 +368,11 @@ PdfToSinglePage.tags=एकल पृष्ठ
home.showJS.title=जावास्क्रिप्ट दिखाएं home.showJS.title=जावास्क्रिप्ट दिखाएं
home.showJS.desc=पीडीएफ़ में डाला गया कोई भी जावास्क्रिप्ट खोजता है और प्रदर्शित करता है home.showJS.desc=पीडीएफ़ में डाला गया कोई भी जावास्क्रिप्ट खोजता है और प्रदर्शित करता है
showJS.tags=गोपनीयकरण, छिपाना, काला करना, काला, मार्कर, छिपा हुआ showJS.tags=जे एस
home.autoRedact.title=स्वतः गोपनीयकरण home.autoRedact.title=स्वतः गोपनीयकरण
home.autoRedact.desc=प्रविष्ट पाठ के आधार पर पीडीएफ़ में पाठ को स्वतः गोपनीयकरित(काला करें) home.autoRedact.desc=प्रविष्ट पाठ के आधार पर पीडीएफ़ में पाठ को स्वतः गोपनीयकरित(काला करें)
showJS.tags=गोपनीयकरण, छिपाना, काला करना, काला, मार्कर, छिपा हुआ autoRedact.tags=गोपनीयकरण, छिपाना, काला करना, काला, मार्कर, छिपा हुआ
home.tableExtraxt.title=PDF से CSV में home.tableExtraxt.title=PDF से CSV में
home.tableExtraxt.desc=CSV में बदलते हुए पीडीएफ़ से तालिकाएँ निकालता है home.tableExtraxt.desc=CSV में बदलते हुए पीडीएफ़ से तालिकाएँ निकालता है
@@ -391,6 +397,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -498,6 +513,7 @@ AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
#sanitizePDF #sanitizePDF
sanitizePDF.title=पीडीएफ़ को सफाई करें sanitizePDF.title=पीडीएफ़ को सफाई करें
sanitizePDF.header=एक पीडीएफ़ फ़ाइल को सफाई करें sanitizePDF.header=एक पीडीएफ़ फ़ाइल को सफाई करें
@@ -621,6 +637,18 @@ compare.document.1=दस्तावेज़ 1
compare.document.2=दस्तावेज़ 2 compare.document.2=दस्तावेज़ 2
compare.submit=तुलना करें compare.submit=तुलना करें
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=हस्ताक्षर sign.title=हस्ताक्षर
@@ -866,7 +894,6 @@ changeMetadata.keywords=कीवर्ड्स:
changeMetadata.modDate=संशोधन तिथि (yyyy/MM/dd HH:mm:ss): changeMetadata.modDate=संशोधन तिथि (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=निर्माता: changeMetadata.producer=निर्माता:
changeMetadata.subject=विषय: changeMetadata.subject=विषय:
changeMetadata.title=शीर्षक:
changeMetadata.trapped=फंसा हुआ: changeMetadata.trapped=फंसा हुआ:
changeMetadata.selectText.4=अन्य मेटाडेटा: changeMetadata.selectText.4=अन्य मेटाडेटा:
changeMetadata.selectText.5=कस्टम मेटाडेटा एंट्री जोड़ें changeMetadata.selectText.5=कस्टम मेटाडेटा एंट्री जोड़ें
@@ -958,7 +985,7 @@ split-by-sections.vertical.label=लंबवत विभाजन
split-by-sections.horizontal.placeholder=क्षैतिज विभाजन की संख्या दर्ज करें split-by-sections.horizontal.placeholder=क्षैतिज विभाजन की संख्या दर्ज करें
split-by-sections.vertical.placeholder=लंबवत विभाजन की संख्या दर्ज करें split-by-sections.vertical.placeholder=लंबवत विभाजन की संख्या दर्ज करें
split-by-sections.submit=PDF को विभाजित करें split-by-sections.submit=PDF को विभाजित करें
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

Some files were not shown because too many files have changed in this diff Show More