Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d59cb18666 | ||
|
|
a772b4fa09 |
67
.github/workflows/mac-unix-artifact-creation.yml
vendored
67
.github/workflows/mac-unix-artifact-creation.yml
vendored
@@ -1,67 +0,0 @@
|
|||||||
name: Create Application Bundles
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'mac'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
create-unix-bundle:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
java-version: '21'
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew bootJar
|
|
||||||
|
|
||||||
- name: Create tar.gz Bundle
|
|
||||||
run: |
|
|
||||||
mkdir -p Stirling-PDF-unix
|
|
||||||
cp build/libs/Stirling-PDF-*.jar Stirling-PDF-unix/Stirling-PDF.jar
|
|
||||||
cp scripts/launcher.sh Stirling-PDF-unix/Stirling-PDF
|
|
||||||
cp src/main/resources/static/favicon.ico Stirling-PDF-unix/icon.png
|
|
||||||
chmod +x Stirling-PDF-unix/Stirling-PDF
|
|
||||||
tar -czf Stirling-PDF-unix.tar.gz Stirling-PDF-unix/
|
|
||||||
|
|
||||||
- name: Upload Unix Bundle
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: unix-bundle
|
|
||||||
path: Stirling-PDF-unix.tar.gz
|
|
||||||
|
|
||||||
create-mac-bundle:
|
|
||||||
runs-on: macos-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
java-version: '21'
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew bootJar
|
|
||||||
|
|
||||||
- name: Create Mac App Bundle
|
|
||||||
run: |
|
|
||||||
cp build/libs/Stirling-PDF-*.jar build/libs/Stirling-PDF.jar
|
|
||||||
chmod +x scripts/create-mac-launcher.sh
|
|
||||||
./scripts/create-mac-launcher.sh
|
|
||||||
|
|
||||||
- name: Create DMG
|
|
||||||
run: |
|
|
||||||
hdiutil create -volname "Stirling-PDF" -srcfolder "Stirling-PDF.app" -ov -format UDZO "Stirling-PDF-mac.dmg"
|
|
||||||
|
|
||||||
- name: Upload Mac Bundle
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: mac-bundle
|
|
||||||
path: Stirling-PDF-mac.dmg
|
|
||||||
22
Dockerfile
22
Dockerfile
@@ -6,7 +6,6 @@ COPY scripts /scripts
|
|||||||
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
|
|
||||||
|
|
||||||
ARG VERSION_TAG
|
ARG VERSION_TAG
|
||||||
|
|
||||||
@@ -19,6 +18,10 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
|||||||
PGID=1000 \
|
PGID=1000 \
|
||||||
UMASK=022
|
UMASK=022
|
||||||
|
|
||||||
|
# Create non-root user first
|
||||||
|
RUN addgroup -S stirlingpdfgroup && \
|
||||||
|
adduser -S stirlingpdfuser -G stirlingpdfgroup
|
||||||
|
|
||||||
# JDK for app
|
# JDK for app
|
||||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
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/community" | tee -a /etc/apk/repositories && \
|
||||||
@@ -31,8 +34,6 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
|||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
qpdf \
|
qpdf \
|
||||||
shadow \
|
|
||||||
su-exec \
|
|
||||||
openssl \
|
openssl \
|
||||||
openssl-dev \
|
openssl-dev \
|
||||||
openjdk21-jre \
|
openjdk21-jre \
|
||||||
@@ -50,15 +51,16 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
|||||||
# uno unoconv and HTML
|
# uno unoconv and HTML
|
||||||
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
|
||||||
fc-cache -f -v && \
|
fc-cache -f -v && \
|
||||||
chmod +x /scripts/* && \
|
|
||||||
chmod +x /scripts/init.sh && \
|
|
||||||
# User permissions
|
# User permissions
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
mkdir -p ${HOME} /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /scripts /usr/share/fonts/custom && \
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
chown -R stirlingpdfuser:stirlingpdfgroup ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
|
chmod -R 755 ${HOME} /configs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
tesseract --list-langs
|
tesseract --list-langs && \
|
||||||
|
chmod -R 777 /logs
|
||||||
|
|
||||||
|
COPY build/libs/*.jar app.jar
|
||||||
|
RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
|
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Build the application
|
# Build stage
|
||||||
FROM gradle:8.11-jdk17 AS build
|
FROM gradle:8.11-jdk17 AS build
|
||||||
|
|
||||||
# Set the working directory
|
# Set the working directory
|
||||||
@@ -7,18 +7,20 @@ WORKDIR /app
|
|||||||
# Copy the entire project to the working directory
|
# Copy the entire project to the working directory
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build the application with DOCKER_ENABLE_SECURITY=false
|
# Build the application
|
||||||
RUN DOCKER_ENABLE_SECURITY=true \
|
RUN DOCKER_ENABLE_SECURITY=true \
|
||||||
./gradlew clean build
|
./gradlew clean build
|
||||||
|
|
||||||
# Main stage
|
# Main stage
|
||||||
FROM alpine:3.20.3
|
FROM alpine:3.20.3
|
||||||
|
|
||||||
# Copy necessary files
|
# Create non-root user first
|
||||||
|
RUN addgroup -S stirlingpdfgroup && \
|
||||||
|
adduser -S stirlingpdfuser -G stirlingpdfgroup
|
||||||
|
|
||||||
COPY scripts /scripts
|
COPY scripts /scripts
|
||||||
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 --from=build /app/build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
ARG VERSION_TAG
|
ARG VERSION_TAG
|
||||||
|
|
||||||
@@ -33,51 +35,45 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
|||||||
FAT_DOCKER=true \
|
FAT_DOCKER=true \
|
||||||
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
||||||
|
|
||||||
|
# Create necessary directories with correct permissions
|
||||||
|
RUN mkdir -p ${HOME} /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /scripts /usr/share/fonts/custom && \
|
||||||
|
chown -R stirlingpdfuser:stirlingpdfgroup ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
|
chmod -R 755 ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom
|
||||||
|
|
||||||
# JDK for app
|
# JDK and other dependencies
|
||||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" >> /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/community" >> /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||||
apk upgrade --no-cache -a && \
|
apk upgrade --no-cache -a && \
|
||||||
apk add --no-cache \
|
apk add --no-cache \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
tzdata \
|
tzdata \
|
||||||
tini \
|
tini \
|
||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
shadow \
|
openssl \
|
||||||
su-exec \
|
openssl-dev \
|
||||||
openssl \
|
openjdk21-jre \
|
||||||
openssl-dev \
|
libreoffice \
|
||||||
openjdk21-jre \
|
poppler-utils \
|
||||||
# Doc conversion
|
qpdf \
|
||||||
libreoffice \
|
tesseract-ocr-data-eng \
|
||||||
# pdftohtml
|
tesseract-ocr-data-fra \
|
||||||
poppler-utils \
|
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
|
||||||
# OCR MY PDF (unpaper for descew and other advanced featues)
|
py3-opencv \
|
||||||
qpdf \
|
python3 \
|
||||||
tesseract-ocr-data-eng \
|
|
||||||
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
|
|
||||||
# CV
|
|
||||||
py3-opencv \
|
|
||||||
# python3/pip
|
|
||||||
python3 \
|
|
||||||
py3-pip && \
|
py3-pip && \
|
||||||
# uno unoconv and HTML
|
|
||||||
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
mkdir -p /usr/share/tessdata && \
|
||||||
fc-cache -f -v && \
|
chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/tessdata /usr/share/fonts/opentype/noto && \
|
||||||
chmod +x /scripts/* && \
|
fc-cache -f -v
|
||||||
chmod +x /scripts/init.sh && \
|
|
||||||
# User permissions
|
COPY build/libs/*.jar app.jar
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
|
|
||||||
tesseract --list-langs
|
|
||||||
|
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
|
|
||||||
# Set user and run command
|
|
||||||
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
||||||
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
|
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
|
||||||
@@ -17,8 +17,11 @@ 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 scripts/installFonts.sh /scripts/installFonts.sh
|
COPY scripts/installFonts.sh /scripts/installFonts.sh
|
||||||
COPY pipeline /pipeline
|
COPY pipeline /pipeline
|
||||||
COPY build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
|
# Create non-root user first
|
||||||
|
RUN addgroup -S stirlingpdfgroup && \
|
||||||
|
adduser -S stirlingpdfuser -G stirlingpdfgroup
|
||||||
|
|
||||||
# Set up necessary directories and permissions
|
# Set up necessary directories and permissions
|
||||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
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/community" | tee -a /etc/apk/repositories && \
|
||||||
@@ -30,18 +33,15 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
|||||||
tini \
|
tini \
|
||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
shadow \
|
|
||||||
su-exec \
|
|
||||||
openjdk21-jre && \
|
openjdk21-jre && \
|
||||||
# User permissions
|
# User permissions
|
||||||
mkdir -p /configs /logs /customFiles /usr/share/fonts/opentype/noto && \
|
mkdir -p ${HOME} /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /scripts /usr/share/fonts/custom && \
|
||||||
chmod +x /scripts/*.sh && \
|
chown -R stirlingpdfuser:stirlingpdfgroup ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
chmod -R 755 ${HOME} /configs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /configs /customFiles /pipeline && \
|
chmod -R 777 /logs
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
|
||||||
|
|
||||||
# Set environment variables
|
COPY build/libs/*.jar app.jar
|
||||||
ENV ENDPOINTS_GROUPS_TO_REMOVE=CLI
|
RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
|
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
|
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -19,7 +19,7 @@ All files and PDFs exist either exclusively on the client side, reside in server
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Enterprise features like SSO Check [here](https://docs.stirlingpdf.com/Enterprise%20Edition)
|
- Enterprise features like SSO Check [here](https://docs.stirlingpdf.com/Enterprise%20Edition)
|
||||||
- Dark mode support
|
- Dark mode support
|
||||||
- Custom download options
|
- Custom download options
|
||||||
- Parallel file processing and downloads
|
- Parallel file processing and downloads
|
||||||
@@ -187,15 +187,15 @@ Certain functionality like `Sign` supports pre-saved files stored at `/customFil
|
|||||||
|
|
||||||
## Supported Languages
|
## Supported Languages
|
||||||
|
|
||||||
Stirling-PDF currently supports 38 languages!
|
Stirling-PDF currently supports 37 languages!
|
||||||
|
|
||||||
| Language | Progress |
|
| Language | Progress |
|
||||||
| -------------------------------------------- | -------------------------------------- |
|
| -------------------------------------------- | -------------------------------------- |
|
||||||
| Arabic (العربية) (ar_AR) |  |
|
| Arabic (العربية) (ar_AR) |  |
|
||||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
||||||
| Basque (Euskara) (eu_ES) |  |
|
| Basque (Euskara) (eu_ES) |  |
|
||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
@@ -208,27 +208,26 @@ Stirling-PDF currently supports 38 languages!
|
|||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
| Italian (Italiano) (it_IT) |  |
|
| Italian (Italiano) (it_IT) |  |
|
||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Persian (فارسی) (fa_IR) |  |
|
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
| Portuguese (Português) (pt_PT) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
| Thai (ไทย) (th_TH) |  |
|
| Thai (ไทย) (th_TH) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
|
|
||||||
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
||||||
|
|
||||||
@@ -241,7 +240,7 @@ Stirling PDF offers a Enterprise edition of its software, This is the same great
|
|||||||
### Whats included
|
### Whats included
|
||||||
|
|
||||||
- Prioritised Support tickets via support@stirlingpdf.com to reach directly to Stirling-PDF team for support and 1:1 meetings where applicable (Provided they come from same email domain registered with us)
|
- Prioritised Support tickets via support@stirlingpdf.com to reach directly to Stirling-PDF team for support and 1:1 meetings where applicable (Provided they come from same email domain registered with us)
|
||||||
- Prioritised Enhancements to Stirling-PDF where applicable
|
- Prioritised Enhancements to Stirling-PDF where applicable
|
||||||
- Base SSO support
|
- Base SSO support
|
||||||
- Advanced SSO such as automated login handling (Coming very soon)
|
- Advanced SSO such as automated login handling (Coming very soon)
|
||||||
- SAML SSO (Coming very soon)
|
- SAML SSO (Coming very soon)
|
||||||
|
|||||||
@@ -14,14 +14,17 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/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
|
||||||
|
user: "stirlingpdfuser"
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
PUID: 1002
|
PUID: 1002
|
||||||
PGID: 1002
|
PGID: 1002
|
||||||
|
LANGS: "ALL"
|
||||||
|
TESSERACT_LANGS: "eng,fra,deu,spa,ita"
|
||||||
UMASK: "022"
|
UMASK: "022"
|
||||||
SYSTEM_DEFAULTLOCALE: en-US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF
|
UI_APPNAME: Stirling-PDF
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/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:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/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:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/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:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/config:/configs:rw
|
- ./stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- ./stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/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:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# scripts/create-mac-launcher.sh
|
|
||||||
|
|
||||||
# Create app structure
|
|
||||||
APP_NAME="Stirling-PDF"
|
|
||||||
APP_BUNDLE="$APP_NAME.app"
|
|
||||||
mkdir -p "$APP_BUNDLE/Contents/"{MacOS,Resources,Java}
|
|
||||||
|
|
||||||
# Convert icon
|
|
||||||
sips -s format icns "src/main/resources/static/favicon.ico" --out "$APP_BUNDLE/Contents/Resources/AppIcon.icns"
|
|
||||||
|
|
||||||
# Create Info.plist
|
|
||||||
cat > "$APP_BUNDLE/Contents/Info.plist" << EOF
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>$APP_NAME</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>AppIcon</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>com.frooodle.stirlingpdf</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>$APP_NAME</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>10.10.0</string>
|
|
||||||
<key>LSEnvironment</key>
|
|
||||||
<dict>
|
|
||||||
<key>BROWSER_OPEN</key>
|
|
||||||
<string>true</string>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create launcher script
|
|
||||||
cat > "$APP_BUNDLE/Contents/MacOS/$APP_NAME" << 'EOF'
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
MIN_JAVA_VERSION="17"
|
|
||||||
PREFERRED_JAVA_VERSION="21"
|
|
||||||
JAVA_DOWNLOAD_URL="https://download.oracle.com/java/21/latest/jdk-21_macos-x64_bin.dmg"
|
|
||||||
|
|
||||||
# Check Java version
|
|
||||||
if type -p java > /dev/null; then
|
|
||||||
_java=java
|
|
||||||
elif [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
|
|
||||||
_java="$JAVA_HOME/bin/java"
|
|
||||||
else
|
|
||||||
osascript -e 'display dialog "Java not found. Please install Java 21." buttons {"Download Java", "Cancel"} default button "Download Java"' \
|
|
||||||
&& open "$JAVA_DOWNLOAD_URL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'.' -f1)
|
|
||||||
if [[ "$version" -lt "$MIN_JAVA_VERSION" ]]; then
|
|
||||||
osascript -e 'display dialog "Wrong Java version. Please install Java 21." buttons {"Download Java", "Cancel"} default button "Download Java"' \
|
|
||||||
&& open "$JAVA_DOWNLOAD_URL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run application
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
||||||
exec java -jar "$DIR/../Java/Stirling-PDF.jar" "$@"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod +x "$APP_BUNDLE/Contents/MacOS/$APP_NAME"
|
|
||||||
|
|
||||||
# Copy JAR file
|
|
||||||
cp "build/libs/Stirling-PDF.jar" "$APP_BUNDLE/Contents/Java/"
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# scripts/create-unix-launcher.sh
|
|
||||||
|
|
||||||
cat > launcher.sh << 'EOF'
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
APP_NAME="Stirling-PDF"
|
|
||||||
MIN_JAVA_VERSION="17"
|
|
||||||
PREFERRED_JAVA_VERSION="21"
|
|
||||||
JAVA_DOWNLOAD_URL="https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz"
|
|
||||||
BROWSER_OPEN="true"
|
|
||||||
|
|
||||||
# Check Java version
|
|
||||||
if type -p java > /dev/null; then
|
|
||||||
_java=java
|
|
||||||
elif [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
|
|
||||||
_java="$JAVA_HOME/bin/java"
|
|
||||||
else
|
|
||||||
echo "Java not found. Please install Java 21."
|
|
||||||
xdg-open "$JAVA_DOWNLOAD_URL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'.' -f1)
|
|
||||||
if [[ "$version" -lt "$MIN_JAVA_VERSION" ]]; then
|
|
||||||
echo "Java version $version detected. Please install Java 21."
|
|
||||||
xdg-open "$JAVA_DOWNLOAD_URL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run application
|
|
||||||
exec java -jar "$(dirname "$0")/Stirling-PDF.jar" "$@"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod +x launcher.sh
|
|
||||||
@@ -66,6 +66,7 @@ ignore = [
|
|||||||
[es_ES]
|
[es_ES]
|
||||||
ignore = [
|
ignore = [
|
||||||
'adminUserSettings.roles',
|
'adminUserSettings.roles',
|
||||||
|
'color',
|
||||||
'error',
|
'error',
|
||||||
'language.direction',
|
'language.direction',
|
||||||
'no',
|
'no',
|
||||||
|
|||||||
@@ -1,37 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Update the user and group IDs as per environment variables
|
|
||||||
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
|
|
||||||
usermod -o -u "$PUID" stirlingpdfuser || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
|
|
||||||
groupmod -o -g "$PGID" stirlingpdfgroup || true
|
|
||||||
fi
|
|
||||||
umask "$UMASK" || true
|
|
||||||
|
|
||||||
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" && "$FAT_DOCKER" != "true" ]]; then
|
|
||||||
echo "issue with calibre in current version, feature currently disabled on Stirling-PDF"
|
|
||||||
#apk add --no-cache calibre@testing
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$FAT_DOCKER" != "true" ]]; then
|
if [[ "$FAT_DOCKER" != "true" ]]; then
|
||||||
/scripts/download-security-jar.sh
|
/scripts/download-security-jar.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$LANGS" ]]; then
|
if [[ -n "$LANGS" ]]; then
|
||||||
/scripts/installFonts.sh $LANGS
|
/scripts/installFonts.sh $LANGS
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Setting permissions and ownership for necessary directories..."
|
exec "$@"
|
||||||
# Attempt to change ownership of directories and files
|
|
||||||
if chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /app.jar; then
|
|
||||||
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /app.jar || true
|
|
||||||
# If chown succeeds, execute the command as stirlingpdfuser
|
|
||||||
exec su-exec stirlingpdfuser "$@"
|
|
||||||
else
|
|
||||||
# If chown fails, execute the command without changing the user context
|
|
||||||
echo "[WARN] Chown failed, running as host user"
|
|
||||||
exec "$@"
|
|
||||||
fi
|
|
||||||
@@ -1,31 +1,39 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# 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/tessdata
|
cp -rn /usr/share/tessdata-original/* /usr/share/tessdata 2>/dev/null || true
|
||||||
cp -rn /usr/share/tessdata-original/* /usr/share/tessdata
|
|
||||||
|
|
||||||
|
# Copy additional tessdata if available
|
||||||
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/tessdata || true;
|
cp -rn /usr/share/tesseract-ocr/4.00/tessdata/* /usr/share/tessdata 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -d /usr/share/tesseract-ocr/5/tessdata ]; then
|
if [ -d /usr/share/tesseract-ocr/5/tessdata ]; then
|
||||||
cp -r /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata || true;
|
cp -rn /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 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 ',' ' ')
|
TES_LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ')
|
||||||
pattern='^[a-zA-Z]{2,4}(_[a-zA-Z]{2,4})?$'
|
pattern='^[a-zA-Z]{2,4}(_[a-zA-Z]{2,4})?$'
|
||||||
# Install each language pack
|
|
||||||
for LANG in $LANGS; do
|
# Log available languages
|
||||||
if [[ $LANG =~ $pattern ]]; then
|
echo "Currently installed languages:"
|
||||||
apk add --no-cache "tesseract-ocr-data-$LANG"
|
tesseract --list-langs
|
||||||
else
|
|
||||||
echo "Skipping invalid language code"
|
echo "Requested additional languages: $TES_LANGS"
|
||||||
fi
|
|
||||||
done
|
# Instead of apk add, download language files from a known source
|
||||||
|
for LANG in $TES_LANGS; do
|
||||||
|
if [[ $LANG =~ $pattern ]]; then
|
||||||
|
# Download to user-writable directory
|
||||||
|
wget -P /usr/share/tessdata/ "https://github.com/tesseract-ocr/tessdata/raw/main/${LANG}.traineddata" || \
|
||||||
|
echo "Failed to download language pack for ${LANG}"
|
||||||
|
else
|
||||||
|
echo "Skipping invalid language code"
|
||||||
|
fi
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/scripts/init-without-ocr.sh "$@"
|
/scripts/init-without-ocr.sh "$@"
|
||||||
@@ -1,67 +1,156 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
LANGS=$1
|
LANGS=$1
|
||||||
|
FONT_DIR="$HOME/.local/share/fonts"
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
# Function to install a font package
|
# Create fonts directory if it doesn't exist
|
||||||
install_font() {
|
mkdir -p "$FONT_DIR"
|
||||||
echo "Installing font package: $1"
|
|
||||||
if ! apk add "$1" --no-cache; then
|
# Function to get latest GitHub release
|
||||||
echo "Failed to install $1"
|
get_latest_release() {
|
||||||
fi
|
local repo=$1
|
||||||
|
local api_url="https://api.github.com/repos/$repo/releases/latest"
|
||||||
|
curl --silent "$api_url" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Install common fonts used across many languages
|
# Function to download and install a font
|
||||||
#common_fonts=(
|
install_font() {
|
||||||
# font-terminus
|
local font_name=$1
|
||||||
# font-dejavu
|
echo "Installing font package: $font_name"
|
||||||
# font-noto
|
|
||||||
# font-noto-cjk
|
# Map font package names to actual font URLs and installation methods
|
||||||
# font-awesome
|
case $font_name in
|
||||||
# font-noto-extra
|
"font-dejavu")
|
||||||
#)
|
local version=$(get_latest_release "dejavu-fonts/dejavu-fonts")
|
||||||
#
|
version=${version#version_} # Remove 'version_' prefix
|
||||||
#for font in "${common_fonts[@]}"; do
|
local url="https://github.com/dejavu-fonts/dejavu-fonts/releases/download/version_${version}/dejavu-fonts-ttf-${version}.tar.bz2"
|
||||||
# install_font $font
|
wget -q "$url" -P "$TEMP_DIR" && \
|
||||||
#done
|
tar xjf "$TEMP_DIR/dejavu-fonts-ttf-${version}.tar.bz2" -C "$TEMP_DIR" && \
|
||||||
|
find "$TEMP_DIR" -name "*.ttf" -exec cp {} "$FONT_DIR/" \;
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto")
|
||||||
|
# Base Noto Sans and Serif
|
||||||
|
wget -q "https://noto-website-2.storage.googleapis.com/pkgs/NotoSans-hinted.zip" -P "$TEMP_DIR" && \
|
||||||
|
wget -q "https://noto-website-2.storage.googleapis.com/pkgs/NotoSerif-hinted.zip" -P "$TEMP_DIR" && \
|
||||||
|
unzip -q "$TEMP_DIR/NotoSans-hinted.zip" -d "$TEMP_DIR/noto-sans" && \
|
||||||
|
unzip -q "$TEMP_DIR/NotoSerif-hinted.zip" -d "$TEMP_DIR/noto-serif" && \
|
||||||
|
cp "$TEMP_DIR/noto-sans"/*.ttf "$FONT_DIR/" && \
|
||||||
|
cp "$TEMP_DIR/noto-serif"/*.ttf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-cjk")
|
||||||
|
# Noto CJK
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/Japanese/NotoSansCJKjp-Regular.otf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/Korean/NotoSansCJKkr-Regular.otf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/SimplifiedChinese/NotoSansCJKsc-Regular.otf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/TraditionalChinese/NotoSansCJKtc-Regular.otf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-arabic")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoNaskhArabic/NotoNaskhArabic-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoKufiArabic/NotoKufiArabic-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-devanagari")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSansDevanagari/NotoSansDevanagari-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSerifDevanagari/NotoSerifDevanagari-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-thai")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSansThai/NotoSansThai-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSerifThai/NotoSerifThai-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-hebrew")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSansHebrew/NotoSansHebrew-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-awesome")
|
||||||
|
local version=$(get_latest_release "FortAwesome/Font-Awesome")
|
||||||
|
wget -q "https://use.fontawesome.com/releases/v${version}/fontawesome-free-${version}-desktop.zip" -P "$TEMP_DIR" && \
|
||||||
|
unzip -q "$TEMP_DIR/fontawesome-free-${version}-desktop.zip" -d "$TEMP_DIR" && \
|
||||||
|
cp "$TEMP_DIR/fontawesome-free-${version}-desktop/otfs"/*.otf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-source-code-pro")
|
||||||
|
local version=$(get_latest_release "adobe-fonts/source-code-pro")
|
||||||
|
wget -q "https://github.com/adobe-fonts/source-code-pro/releases/download/${version}/TTF-source-code-pro-${version}.zip" -P "$TEMP_DIR" && \
|
||||||
|
unzip -q "$TEMP_DIR/TTF-source-code-pro-${version}.zip" -d "$TEMP_DIR/source-code-pro" && \
|
||||||
|
cp "$TEMP_DIR/source-code-pro"/*.ttf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-vollkorn")
|
||||||
|
wget -q "https://github.com/FAlthausen/Vollkorn-Typeface/raw/main/fonts/TTF/Vollkorn-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-liberation")
|
||||||
|
wget -q "https://github.com/liberationfonts/liberation-fonts/files/7261482/liberation-fonts-ttf-2.1.5.tar.gz" -P "$TEMP_DIR" && \
|
||||||
|
tar xzf "$TEMP_DIR/liberation-fonts-ttf-2.1.5.tar.gz" -C "$TEMP_DIR" && \
|
||||||
|
cp "$TEMP_DIR/liberation-fonts-ttf-2.1.5"/*.ttf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Completed installation attempt for $font_name"
|
||||||
|
}
|
||||||
|
|
||||||
# Map languages to specific font packages
|
# Enhanced language-specific font mappings
|
||||||
declare -A language_fonts=(
|
declare -A language_fonts=(
|
||||||
["ar_AR"]="font-noto-arabic"
|
["ar_AR"]="font-noto-arabic"
|
||||||
["zh_CN"]="font-isas-misc"
|
["zh_CN"]="font-noto-cjk"
|
||||||
["zh_TW"]="font-isas-misc"
|
["zh_TW"]="font-noto-cjk"
|
||||||
["ja_JP"]="font-noto font-noto-thai font-noto-tibetan font-ipa font-sony-misc font-jis-misc"
|
["ja_JP"]="font-noto font-noto-cjk"
|
||||||
["ru_RU"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
["ru_RU"]="font-noto font-liberation font-vollkorn"
|
||||||
["sr_LATN_RS"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
["sr_LATN_RS"]="font-noto font-liberation"
|
||||||
["uk_UA"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
["uk_UA"]="font-noto font-liberation"
|
||||||
["ko_KR"]="font-noto font-noto-thai font-noto-tibetan"
|
["ko_KR"]="font-noto font-noto-cjk"
|
||||||
["el_GR"]="font-noto"
|
["el_GR"]="font-noto"
|
||||||
["hi_IN"]="font-noto-devanagari"
|
["hi_IN"]="font-noto-devanagari"
|
||||||
["bg_BG"]="font-vollkorn font-misc-cyrillic"
|
["bg_BG"]="font-noto font-liberation"
|
||||||
["GENERAL"]="font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra"
|
["th_TH"]="font-noto-thai"
|
||||||
|
["he_IL"]="font-noto-hebrew"
|
||||||
|
["GENERAL"]="font-noto font-dejavu font-liberation font-source-code-pro font-awesome"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install fonts for other languages which generally do not need special packages beyond 'font-noto'
|
# Install fonts based on specified languages
|
||||||
other_langs=("en_GB" "en_US" "de_DE" "fr_FR" "es_ES" "ca_CA" "it_IT" "pt_BR" "nl_NL" "sv_SE" "pl_PL" "ro_RO" "hu_HU" "tr_TR" "id_ID" "eu_ES")
|
|
||||||
if [[ $LANGS == "ALL" ]]; then
|
if [[ $LANGS == "ALL" ]]; then
|
||||||
# Install all fonts from the language_fonts map
|
# Install all fonts from the language_fonts map
|
||||||
|
declare -A installed_fonts
|
||||||
for fonts in "${language_fonts[@]}"; do
|
for fonts in "${language_fonts[@]}"; do
|
||||||
for font in $fonts; do
|
for font in $fonts; do
|
||||||
install_font $font
|
if [[ -z "${installed_fonts[$font]}" ]]; then
|
||||||
|
install_font "$font"
|
||||||
|
installed_fonts[$font]=1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
# Split comma-separated languages and install necessary fonts
|
# Split comma-separated languages and install necessary fonts
|
||||||
|
declare -A installed_fonts
|
||||||
IFS=',' read -ra LANG_CODES <<< "$LANGS"
|
IFS=',' read -ra LANG_CODES <<< "$LANGS"
|
||||||
for code in "${LANG_CODES[@]}"; do
|
for code in "${LANG_CODES[@]}"; do
|
||||||
if [[ " ${other_langs[@]} " =~ " ${code} " ]]; then
|
fonts_to_install=${language_fonts[$code]}
|
||||||
install_font font-noto
|
if [ ! -z "$fonts_to_install" ]; then
|
||||||
else
|
for font in $fonts_to_install; do
|
||||||
fonts_to_install=${language_fonts[$code]}
|
if [[ -z "${installed_fonts[$font]}" ]]; then
|
||||||
if [ ! -z "$fonts_to_install" ]; then
|
install_font "$font"
|
||||||
for font in $fonts_to_install; do
|
installed_fonts[$font]=1
|
||||||
install_font $font
|
fi
|
||||||
done
|
done
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
|
||||||
|
# Update font cache
|
||||||
|
if command -v fc-cache >/dev/null; then
|
||||||
|
fc-cache -f "$FONT_DIR"
|
||||||
|
echo "Font cache updated"
|
||||||
|
else
|
||||||
|
echo "Warning: fc-cache not found. You may need to manually update your font cache"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Font installation completed. Fonts installed in: $FONT_DIR"
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
MIN_JAVA_VERSION="17"
|
|
||||||
PREFERRED_JAVA_VERSION="21"
|
|
||||||
JAVA_DOWNLOAD_URL="https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz"
|
|
||||||
BROWSER_OPEN="true"
|
|
||||||
|
|
||||||
# Check Java version
|
|
||||||
if type -p java > /dev/null; then
|
|
||||||
_java=java
|
|
||||||
elif [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
|
|
||||||
_java="$JAVA_HOME/bin/java"
|
|
||||||
else
|
|
||||||
echo "Java not found. Please install Java 21."
|
|
||||||
xdg-open "$JAVA_DOWNLOAD_URL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'.' -f1)
|
|
||||||
if [[ "$version" -lt "$MIN_JAVA_VERSION" ]]; then
|
|
||||||
echo "Java version $version detected. Please install Java 21."
|
|
||||||
xdg-open "$JAVA_DOWNLOAD_URL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run application
|
|
||||||
exec java -jar "$(dirname "$0")/Stirling-PDF.jar" "$@"
|
|
||||||
@@ -28,7 +28,7 @@ public class LicenseKeyChecker {
|
|||||||
this.checkLicense();
|
this.checkLicense();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(initialDelay = 604800000,fixedRate = 604800000) // 7 days in milliseconds
|
@Scheduled(initialDelay = 604800000, fixedRate = 604800000) // 7 days in milliseconds
|
||||||
public void checkLicensePeriodically() {
|
public void checkLicensePeriodically() {
|
||||||
checkLicense();
|
checkLicense();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -595,7 +595,9 @@ public class GetInfoOnPDF {
|
|||||||
|
|
||||||
permissionsNode.put("Document Assembly", getPermissionState(ap.canAssembleDocument()));
|
permissionsNode.put("Document Assembly", getPermissionState(ap.canAssembleDocument()));
|
||||||
permissionsNode.put("Extracting Content", getPermissionState(ap.canExtractContent()));
|
permissionsNode.put("Extracting Content", getPermissionState(ap.canExtractContent()));
|
||||||
permissionsNode.put("Extracting for accessibility", getPermissionState(ap.canExtractForAccessibility()));
|
permissionsNode.put(
|
||||||
|
"Extracting for accessibility",
|
||||||
|
getPermissionState(ap.canExtractForAccessibility()));
|
||||||
permissionsNode.put("Form Filling", getPermissionState(ap.canFillInForm()));
|
permissionsNode.put("Form Filling", getPermissionState(ap.canFillInForm()));
|
||||||
permissionsNode.put("Modifying", getPermissionState(ap.canModify()));
|
permissionsNode.put("Modifying", getPermissionState(ap.canModify()));
|
||||||
permissionsNode.put("Modifying annotations", getPermissionState(ap.canModifyAnnotations()));
|
permissionsNode.put("Modifying annotations", getPermissionState(ap.canModifyAnnotations()));
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ package stirling.software.SPDF.controller.api.security;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateExpiredException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.CertificateNotYetValidException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
@@ -41,7 +42,6 @@ import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
|||||||
@RequestMapping("/api/v1/security")
|
@RequestMapping("/api/v1/security")
|
||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class ValidateSignatureController {
|
public class ValidateSignatureController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||||
private final CertificateValidationService certValidationService;
|
private final CertificateValidationService certValidationService;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ public class ValidateSignatureController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Validate PDF Digital Signature",
|
summary = "Validate PDF Digital Signature",
|
||||||
description =
|
description =
|
||||||
"Validates the digital signatures in a PDF file against default or custom certificates. Input:PDF Output:JSON Type:SISO")
|
"Validates digital signatures in a PDF file against default or custom certificates.")
|
||||||
@PostMapping(value = "/validate-signature")
|
@PostMapping(value = "/validate-signature")
|
||||||
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
|
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
|
||||||
@ModelAttribute SignatureValidationRequest request) throws IOException {
|
@ModelAttribute SignatureValidationRequest request) throws IOException {
|
||||||
@@ -80,7 +80,6 @@ public class ValidateSignatureController {
|
|||||||
|
|
||||||
for (PDSignature sig : signatures) {
|
for (PDSignature sig : signatures) {
|
||||||
SignatureValidationResult result = new SignatureValidationResult();
|
SignatureValidationResult result = new SignatureValidationResult();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[] signedContent = sig.getSignedContent(file.getInputStream());
|
byte[] signedContent = sig.getSignedContent(file.getInputStream());
|
||||||
byte[] signatureBytes = sig.getContents(file.getInputStream());
|
byte[] signatureBytes = sig.getContents(file.getInputStream());
|
||||||
@@ -92,77 +91,90 @@ public class ValidateSignatureController {
|
|||||||
SignerInformationStore signerStore = signedData.getSignerInfos();
|
SignerInformationStore signerStore = signedData.getSignerInfos();
|
||||||
|
|
||||||
for (SignerInformation signer : signerStore.getSigners()) {
|
for (SignerInformation signer : signerStore.getSigners()) {
|
||||||
X509CertificateHolder certHolder = (X509CertificateHolder) certStore.getMatches(signer.getSID()).iterator().next();
|
X509CertificateHolder certHolder =
|
||||||
X509Certificate cert = new JcaX509CertificateConverter().getCertificate(certHolder);
|
(X509CertificateHolder)
|
||||||
|
certStore.getMatches(signer.getSID()).iterator().next();
|
||||||
|
X509Certificate cert =
|
||||||
|
new JcaX509CertificateConverter().getCertificate(certHolder);
|
||||||
|
|
||||||
boolean isValid = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert));
|
// Basic signature validation
|
||||||
result.setValid(isValid);
|
result.setValid(
|
||||||
|
signer.verify(
|
||||||
|
new JcaSimpleSignerInfoVerifierBuilder().build(cert)));
|
||||||
|
|
||||||
// Additional validations
|
// Perform chain validation
|
||||||
result.setChainValid(customCert != null
|
CertificateValidationService.ValidationResult chainResult;
|
||||||
? certValidationService.validateCertificateChainWithCustomCert(cert, customCert)
|
if (customCert != null) {
|
||||||
: certValidationService.validateCertificateChain(cert));
|
chainResult =
|
||||||
|
certValidationService.validateWithCustomCert(cert, customCert);
|
||||||
result.setTrustValid(customCert != null
|
} else {
|
||||||
? certValidationService.validateTrustWithCustomCert(cert, customCert)
|
chainResult = certValidationService.validateCertificateChain(cert);
|
||||||
: certValidationService.validateTrustStore(cert));
|
|
||||||
|
|
||||||
result.setNotRevoked(!certValidationService.isRevoked(cert));
|
|
||||||
result.setNotExpired(!cert.getNotAfter().before(new Date()));
|
|
||||||
|
|
||||||
// Set basic signature info
|
|
||||||
result.setSignerName(sig.getName());
|
|
||||||
result.setSignatureDate(sig.getSignDate().getTime().toString());
|
|
||||||
result.setReason(sig.getReason());
|
|
||||||
result.setLocation(sig.getLocation());
|
|
||||||
|
|
||||||
// Set new certificate details
|
|
||||||
result.setIssuerDN(cert.getIssuerX500Principal().getName());
|
|
||||||
result.setSubjectDN(cert.getSubjectX500Principal().getName());
|
|
||||||
result.setSerialNumber(cert.getSerialNumber().toString(16)); // Hex format
|
|
||||||
result.setValidFrom(cert.getNotBefore().toString());
|
|
||||||
result.setValidUntil(cert.getNotAfter().toString());
|
|
||||||
result.setSignatureAlgorithm(cert.getSigAlgName());
|
|
||||||
|
|
||||||
// Get key size (if possible)
|
|
||||||
try {
|
|
||||||
result.setKeySize(((RSAPublicKey) cert.getPublicKey()).getModulus().bitLength());
|
|
||||||
} catch (Exception e) {
|
|
||||||
// If not RSA or error, set to 0
|
|
||||||
result.setKeySize(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.setVersion(String.valueOf(cert.getVersion()));
|
result.setChainValid(chainResult.isValid());
|
||||||
|
result.setTrustValid(chainResult.isValid());
|
||||||
// Set key usage
|
result.setNotExpired(!chainResult.isExpired());
|
||||||
List<String> keyUsages = new ArrayList<>();
|
|
||||||
boolean[] keyUsageFlags = cert.getKeyUsage();
|
// Check if signature was valid at the time of signing
|
||||||
if (keyUsageFlags != null) {
|
if (sig.getSignDate() != null) {
|
||||||
String[] keyUsageLabels = {
|
try {
|
||||||
"Digital Signature", "Non-Repudiation", "Key Encipherment",
|
cert.checkValidity(sig.getSignDate().getTime());
|
||||||
"Data Encipherment", "Key Agreement", "Certificate Signing",
|
result.setValidAtTimeOfSigning(true);
|
||||||
"CRL Signing", "Encipher Only", "Decipher Only"
|
} catch (CertificateExpiredException
|
||||||
};
|
| CertificateNotYetValidException e) {
|
||||||
for (int i = 0; i < keyUsageFlags.length; i++) {
|
result.setValidAtTimeOfSigning(false);
|
||||||
if (keyUsageFlags[i]) {
|
|
||||||
keyUsages.add(keyUsageLabels[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.setKeyUsages(keyUsages);
|
|
||||||
|
// Set signature info
|
||||||
// Check if self-signed
|
populateSignatureInfo(result, sig, cert);
|
||||||
result.setSelfSigned(cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal()));
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
result.setValid(false);
|
result.setValid(false);
|
||||||
result.setErrorMessage("Signature validation failed: " + e.getMessage());
|
result.setErrorMessage("Signature validation failed: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
results.add(result);
|
results.add(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResponseEntity.ok(results);
|
return ResponseEntity.ok(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void populateSignatureInfo(
|
||||||
|
SignatureValidationResult result, PDSignature sig, X509Certificate cert) {
|
||||||
|
result.setSignerName(sig.getName());
|
||||||
|
result.setSignatureDate(sig.getSignDate().getTime().toString());
|
||||||
|
result.setReason(sig.getReason());
|
||||||
|
result.setLocation(sig.getLocation());
|
||||||
|
result.setIssuerDN(cert.getIssuerX500Principal().getName());
|
||||||
|
result.setSubjectDN(cert.getSubjectX500Principal().getName());
|
||||||
|
result.setSerialNumber(cert.getSerialNumber().toString(16));
|
||||||
|
result.setValidFrom(cert.getNotBefore().toString());
|
||||||
|
result.setValidUntil(cert.getNotAfter().toString());
|
||||||
|
result.setSignatureAlgorithm(cert.getSigAlgName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
result.setKeySize(((RSAPublicKey) cert.getPublicKey()).getModulus().bitLength());
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setKeySize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setVersion(String.valueOf(cert.getVersion()));
|
||||||
|
|
||||||
|
List<String> keyUsages = new ArrayList<>();
|
||||||
|
boolean[] keyUsageFlags = cert.getKeyUsage();
|
||||||
|
if (keyUsageFlags != null) {
|
||||||
|
String[] keyUsageLabels = {
|
||||||
|
"Digital Signature", "Non-Repudiation", "Key Encipherment",
|
||||||
|
"Data Encipherment", "Key Agreement", "Certificate Signing",
|
||||||
|
"CRL Signing", "Encipher Only", "Decipher Only"
|
||||||
|
};
|
||||||
|
for (int i = 0; i < keyUsageFlags.length; i++) {
|
||||||
|
if (keyUsageFlags[i]) {
|
||||||
|
keyUsages.add(keyUsageLabels[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.setKeyUsages(keyUsages);
|
||||||
|
result.setSelfSigned(cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ public class WatermarkController {
|
|||||||
float opacity = request.getOpacity();
|
float opacity = request.getOpacity();
|
||||||
int widthSpacer = request.getWidthSpacer();
|
int widthSpacer = request.getWidthSpacer();
|
||||||
int heightSpacer = request.getHeightSpacer();
|
int heightSpacer = request.getHeightSpacer();
|
||||||
String customColor = request.getCustomColor();
|
|
||||||
boolean convertPdfToImage = request.isConvertPDFToImage();
|
boolean convertPdfToImage = request.isConvertPDFToImage();
|
||||||
|
|
||||||
// Load the input PDF
|
// Load the input PDF
|
||||||
@@ -98,8 +97,7 @@ public class WatermarkController {
|
|||||||
widthSpacer,
|
widthSpacer,
|
||||||
heightSpacer,
|
heightSpacer,
|
||||||
fontSize,
|
fontSize,
|
||||||
alphabet,
|
alphabet);
|
||||||
customColor);
|
|
||||||
} else if ("image".equalsIgnoreCase(watermarkType)) {
|
} else if ("image".equalsIgnoreCase(watermarkType)) {
|
||||||
addImageWatermark(
|
addImageWatermark(
|
||||||
contentStream,
|
contentStream,
|
||||||
@@ -138,8 +136,7 @@ public class WatermarkController {
|
|||||||
int widthSpacer,
|
int widthSpacer,
|
||||||
int heightSpacer,
|
int heightSpacer,
|
||||||
float fontSize,
|
float fontSize,
|
||||||
String alphabet,
|
String alphabet)
|
||||||
String colorString)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String resourceDir = "";
|
String resourceDir = "";
|
||||||
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||||
@@ -176,18 +173,7 @@ public class WatermarkController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentStream.setFont(font, fontSize);
|
contentStream.setFont(font, fontSize);
|
||||||
|
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
|
||||||
Color redactColor;
|
|
||||||
try {
|
|
||||||
if (!colorString.startsWith("#")) {
|
|
||||||
colorString = "#" + colorString;
|
|
||||||
}
|
|
||||||
redactColor = Color.decode(colorString);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
|
|
||||||
redactColor = Color.LIGHT_GRAY;
|
|
||||||
}
|
|
||||||
contentStream.setNonStrokingColor(redactColor);
|
|
||||||
|
|
||||||
String[] textLines = watermarkText.split("\\\\n");
|
String[] textLines = watermarkText.split("\\\\n");
|
||||||
float maxLineWidth = 0;
|
float maxLineWidth = 0;
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ public class AddWatermarkRequest extends PDFFile {
|
|||||||
@Schema(description = "The height spacer between watermark elements", example = "50")
|
@Schema(description = "The height spacer between watermark elements", example = "50")
|
||||||
private int heightSpacer;
|
private int heightSpacer;
|
||||||
|
|
||||||
@Schema(description = "The color for watermark", defaultValue = "#d3d3d3")
|
|
||||||
private String customColor = "#d3d3d3";
|
|
||||||
|
|
||||||
@Schema(description = "Convert the redacted PDF to an image", defaultValue = "false")
|
@Schema(description = "Convert the redacted PDF to an image", defaultValue = "false")
|
||||||
private boolean convertPDFToImage;
|
private boolean convertPDFToImage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ public class SignatureValidationResult {
|
|||||||
private boolean trustValid;
|
private boolean trustValid;
|
||||||
private boolean notExpired;
|
private boolean notExpired;
|
||||||
private boolean notRevoked;
|
private boolean notRevoked;
|
||||||
|
private boolean validAtTimeOfSigning;
|
||||||
private String issuerDN; // Certificate issuer's Distinguished Name
|
|
||||||
private String subjectDN; // Certificate subject's Distinguished Name
|
private String issuerDN; // Certificate issuer's Distinguished Name
|
||||||
private String serialNumber; // Certificate serial number
|
private String subjectDN; // Certificate subject's Distinguished Name
|
||||||
private String validFrom; // Certificate validity start date
|
private String serialNumber; // Certificate serial number
|
||||||
private String validUntil; // Certificate validity end date
|
private String validFrom; // Certificate validity start date
|
||||||
private String signatureAlgorithm;// Algorithm used for signing
|
private String validUntil; // Certificate validity end date
|
||||||
private int keySize; // Key size in bits
|
private String signatureAlgorithm; // Algorithm used for signing
|
||||||
private String version; // Certificate version
|
private int keySize; // Key size in bits
|
||||||
private List<String> keyUsages; // List of key usage purposes
|
private String version; // Certificate version
|
||||||
private boolean isSelfSigned; // Whether the certificate is self-signed
|
private List<String> keyUsages; // List of key usage purposes
|
||||||
|
private boolean isSelfSigned; // Whether the certificate is self-signed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
package stirling.software.SPDF.service;
|
package stirling.software.SPDF.service;
|
||||||
|
|
||||||
import io.github.pixee.security.BoundedLineReader;
|
import java.io.*;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.cert.*;
|
||||||
import java.security.cert.CertPath;
|
import java.security.cert.CertPath;
|
||||||
import java.security.cert.CertPathValidator;
|
import java.security.cert.CertPathValidator;
|
||||||
import java.security.cert.CertificateExpiredException;
|
import java.security.cert.CertificateExpiredException;
|
||||||
@@ -16,84 +14,126 @@ import java.security.cert.CertificateNotYetValidException;
|
|||||||
import java.security.cert.PKIXParameters;
|
import java.security.cert.PKIXParameters;
|
||||||
import java.security.cert.TrustAnchor;
|
import java.security.cert.TrustAnchor;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class CertificateValidationService {
|
public class CertificateValidationService {
|
||||||
private KeyStore trustStore;
|
private KeyStore trustStore;
|
||||||
|
private static final String AATL_RESOURCE = "/tl12.acrobatsecuritysettings";
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
private void initializeTrustStore() throws Exception {
|
private void initializeTrustStore() throws Exception {
|
||||||
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
trustStore.load(null, null);
|
trustStore.load(null, null);
|
||||||
loadMozillaCertificates();
|
loadAATLCertificatesFromPDF();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMozillaCertificates() throws Exception {
|
private void loadAATLCertificatesFromPDF() throws Exception {
|
||||||
try (InputStream is = getClass().getResourceAsStream("/certdata.txt")) {
|
log.debug("Starting AATL certificate loading from PDF...");
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
|
||||||
String line;
|
|
||||||
StringBuilder certData = new StringBuilder();
|
|
||||||
boolean inCert = false;
|
|
||||||
int certCount = 0;
|
|
||||||
|
|
||||||
while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) {
|
try (InputStream pdfStream = new ClassPathResource(AATL_RESOURCE).getInputStream()) {
|
||||||
if (line.startsWith("CKA_VALUE MULTILINE_OCTAL")) {
|
PDDocument document = Loader.loadPDF(pdfStream.readAllBytes());
|
||||||
inCert = true;
|
|
||||||
certData = new StringBuilder();
|
PDEmbeddedFilesNameTreeNode embeddedFiles =
|
||||||
continue;
|
document.getDocumentCatalog().getNames().getEmbeddedFiles();
|
||||||
}
|
Map<String, PDComplexFileSpecification> files = embeddedFiles.getNames();
|
||||||
if (inCert) {
|
|
||||||
if ("END".equals(line)) {
|
for (Map.Entry<String, PDComplexFileSpecification> entry : files.entrySet()) {
|
||||||
inCert = false;
|
log.debug(entry.getKey());
|
||||||
byte[] certBytes = parseOctalData(certData.toString());
|
if (entry.getKey().equals("SecuritySettings.xml")) {
|
||||||
if (certBytes != null) {
|
byte[] xmlContent = entry.getValue().getEmbeddedFile().toByteArray();
|
||||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
processSecuritySettingsXML(xmlContent);
|
||||||
X509Certificate cert =
|
break;
|
||||||
(X509Certificate)
|
|
||||||
cf.generateCertificate(
|
|
||||||
new ByteArrayInputStream(certBytes));
|
|
||||||
trustStore.setCertificateEntry("mozilla-cert-" + certCount++, cert);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
certData.append(line).append("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] parseOctalData(String data) {
|
private void processSecuritySettingsXML(byte[] xmlContent) throws Exception {
|
||||||
try {
|
// Simple XML parsing using String operations
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
String xmlString = new String(xmlContent, "UTF-8");
|
||||||
String[] tokens = data.split("\\\\");
|
int certCount = 0;
|
||||||
for (String token : tokens) {
|
int failedCerts = 0;
|
||||||
token = token.trim();
|
|
||||||
if (!token.isEmpty()) {
|
// Find all Certificate tags
|
||||||
baos.write(Integer.parseInt(token, 8));
|
String startTag = "<Certificate>";
|
||||||
|
String endTag = "</Certificate>";
|
||||||
|
int startIndex = 0;
|
||||||
|
|
||||||
|
while ((startIndex = xmlString.indexOf(startTag, startIndex)) != -1) {
|
||||||
|
int endIndex = xmlString.indexOf(endTag, startIndex);
|
||||||
|
if (endIndex == -1) break;
|
||||||
|
|
||||||
|
// Extract certificate data
|
||||||
|
String certData = xmlString.substring(startIndex + startTag.length(), endIndex).trim();
|
||||||
|
startIndex = endIndex + endTag.length();
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] certBytes = Base64.getDecoder().decode(certData);
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
X509Certificate cert =
|
||||||
|
(X509Certificate)
|
||||||
|
cf.generateCertificate(new ByteArrayInputStream(certBytes));
|
||||||
|
|
||||||
|
// Only store root certificates (self-signed)
|
||||||
|
if (cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal())) {
|
||||||
|
trustStore.setCertificateEntry("aatl-cert-" + certCount, cert);
|
||||||
|
log.trace(
|
||||||
|
"Successfully loaded AATL root certificate #"
|
||||||
|
+ certCount
|
||||||
|
+ "\n Subject: "
|
||||||
|
+ cert.getSubjectX500Principal().getName()
|
||||||
|
+ "\n Valid until: "
|
||||||
|
+ cert.getNotAfter());
|
||||||
|
certCount++;
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failedCerts++;
|
||||||
|
log.error("Failed to process AATL certificate: " + e.getMessage());
|
||||||
}
|
}
|
||||||
return baos.toByteArray();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug("AATL Certificate loading completed:");
|
||||||
|
log.debug(" Total root certificates successfully loaded: " + certCount);
|
||||||
|
log.debug(" Failed certificates: " + failedCerts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateCertificateChain(X509Certificate cert) {
|
@Data
|
||||||
|
public static class ValidationResult {
|
||||||
|
private boolean valid;
|
||||||
|
private boolean expired;
|
||||||
|
private boolean validAtSigningTime;
|
||||||
|
private String errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationResult validateCertificateChain(X509Certificate signerCert) {
|
||||||
|
ValidationResult result = new ValidationResult();
|
||||||
try {
|
try {
|
||||||
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
|
// Build the certificate chain
|
||||||
|
List<X509Certificate> certChain = buildCertificateChain(signerCert);
|
||||||
|
|
||||||
|
// Create certificate path
|
||||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
List<X509Certificate> certList = Arrays.asList(cert);
|
CertPath certPath = cf.generateCertPath(certChain);
|
||||||
CertPath certPath = cf.generateCertPath(certList);
|
|
||||||
|
|
||||||
|
// Set up trust anchors
|
||||||
Set<TrustAnchor> anchors = new HashSet<>();
|
Set<TrustAnchor> anchors = new HashSet<>();
|
||||||
Enumeration<String> aliases = trustStore.aliases();
|
Enumeration<String> aliases = trustStore.aliases();
|
||||||
while (aliases.hasMoreElements()) {
|
while (aliases.hasMoreElements()) {
|
||||||
@@ -103,31 +143,113 @@ public class CertificateValidationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up validation parameters
|
||||||
PKIXParameters params = new PKIXParameters(anchors);
|
PKIXParameters params = new PKIXParameters(anchors);
|
||||||
params.setRevocationEnabled(false);
|
params.setRevocationEnabled(false);
|
||||||
|
|
||||||
|
// Validate the path
|
||||||
|
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
|
||||||
validator.validate(certPath, params);
|
validator.validate(certPath, params);
|
||||||
return true;
|
|
||||||
|
result.setValid(true);
|
||||||
|
result.setExpired(isExpired(signerCert));
|
||||||
|
|
||||||
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
result.setValid(false);
|
||||||
|
result.setErrorMessage(e.getMessage());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateTrustStore(X509Certificate cert) {
|
public ValidationResult validateWithCustomCert(
|
||||||
|
X509Certificate signerCert, X509Certificate customCert) {
|
||||||
|
ValidationResult result = new ValidationResult();
|
||||||
|
try {
|
||||||
|
// Build the complete chain from signer cert
|
||||||
|
List<X509Certificate> certChain = buildCertificateChain(signerCert);
|
||||||
|
|
||||||
|
// Check if custom cert matches any cert in the chain
|
||||||
|
boolean matchFound = false;
|
||||||
|
for (X509Certificate chainCert : certChain) {
|
||||||
|
if (chainCert.equals(customCert)) {
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchFound) {
|
||||||
|
// Check if custom cert is a valid issuer for any cert in the chain
|
||||||
|
for (X509Certificate chainCert : certChain) {
|
||||||
|
try {
|
||||||
|
chainCert.verify(customCert.getPublicKey());
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Continue checking next cert
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setValid(matchFound);
|
||||||
|
if (!matchFound) {
|
||||||
|
result.setErrorMessage(
|
||||||
|
"Custom certificate is not part of the chain and is not a valid issuer");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setValid(false);
|
||||||
|
result.setErrorMessage(e.getMessage());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<X509Certificate> buildCertificateChain(X509Certificate signerCert)
|
||||||
|
throws CertificateException {
|
||||||
|
List<X509Certificate> chain = new ArrayList<>();
|
||||||
|
chain.add(signerCert);
|
||||||
|
|
||||||
|
X509Certificate current = signerCert;
|
||||||
|
while (!isSelfSigned(current)) {
|
||||||
|
X509Certificate issuer = findIssuer(current);
|
||||||
|
if (issuer == null) break;
|
||||||
|
chain.add(issuer);
|
||||||
|
current = issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSelfSigned(X509Certificate cert) {
|
||||||
|
return cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal());
|
||||||
|
}
|
||||||
|
|
||||||
|
private X509Certificate findIssuer(X509Certificate cert) throws CertificateException {
|
||||||
try {
|
try {
|
||||||
Enumeration<String> aliases = trustStore.aliases();
|
Enumeration<String> aliases = trustStore.aliases();
|
||||||
while (aliases.hasMoreElements()) {
|
while (aliases.hasMoreElements()) {
|
||||||
Object trustCert = trustStore.getCertificate(aliases.nextElement());
|
Certificate trustCert = trustStore.getCertificate(aliases.nextElement());
|
||||||
if (trustCert instanceof X509Certificate && cert.equals(trustCert)) {
|
if (trustCert instanceof X509Certificate) {
|
||||||
return true;
|
X509Certificate x509TrustCert = (X509Certificate) trustCert;
|
||||||
|
if (cert.getIssuerX500Principal()
|
||||||
|
.equals(x509TrustCert.getSubjectX500Principal())) {
|
||||||
|
try {
|
||||||
|
cert.verify(x509TrustCert.getPublicKey());
|
||||||
|
return x509TrustCert;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Continue searching if verification fails
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
} catch (KeyStoreException e) {
|
} catch (KeyStoreException e) {
|
||||||
return false;
|
throw new CertificateException("Error accessing trust store", e);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRevoked(X509Certificate cert) {
|
private boolean isExpired(X509Certificate cert) {
|
||||||
try {
|
try {
|
||||||
cert.checkValidity();
|
cert.checkValidity();
|
||||||
return false;
|
return false;
|
||||||
@@ -135,23 +257,4 @@ public class CertificateValidationService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateCertificateChainWithCustomCert(
|
|
||||||
X509Certificate cert, X509Certificate customCert) {
|
|
||||||
try {
|
|
||||||
cert.verify(customCert.getPublicKey());
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean validateTrustWithCustomCert(X509Certificate cert, X509Certificate customCert) {
|
|
||||||
try {
|
|
||||||
// Compare the issuer of the signature certificate with the custom certificate
|
|
||||||
return cert.getIssuerX500Principal().equals(customCert.getSubjectX500Principal());
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=تشفير
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=إضافة علامة مائية
|
watermark.title=إضافة علامة مائية
|
||||||
watermark.header=إضافة علامة مائية
|
watermark.header=إضافة علامة مائية
|
||||||
watermark.customColor=لون نص مخصص
|
|
||||||
watermark.selectText.1=حدد PDF لإضافة العلامة المائية إليه:
|
watermark.selectText.1=حدد PDF لإضافة العلامة المائية إليه:
|
||||||
watermark.selectText.2=نص العلامة المائية:
|
watermark.selectText.2=نص العلامة المائية:
|
||||||
watermark.selectText.3=حجم الخط:
|
watermark.selectText.3=حجم الخط:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Şifrlə
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Watermark Əlavə Et
|
watermark.title=Watermark Əlavə Et
|
||||||
watermark.header=Watermark Əlavə Et
|
watermark.header=Watermark Əlavə Et
|
||||||
watermark.customColor=Fərdi Mətn Rəngi
|
|
||||||
watermark.selectText.1=Watermark əlavə olunacaq PDF-i seç
|
watermark.selectText.1=Watermark əlavə olunacaq PDF-i seç
|
||||||
watermark.selectText.2=Watermark Mətni:
|
watermark.selectText.2=Watermark Mətni:
|
||||||
watermark.selectText.3=Şrift Ölçüsü:
|
watermark.selectText.3=Şrift Ölçüsü:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Шифроване
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Добавяне на воден знак
|
watermark.title=Добавяне на воден знак
|
||||||
watermark.header=Добавяне на воден знак
|
watermark.header=Добавяне на воден знак
|
||||||
watermark.customColor=Персонализиран цвят на текста
|
|
||||||
watermark.selectText.1=Изберете PDF, към който да добавите воден знак:
|
watermark.selectText.1=Изберете PDF, към който да добавите воден знак:
|
||||||
watermark.selectText.2=Текст на воден знак:
|
watermark.selectText.2=Текст на воден знак:
|
||||||
watermark.selectText.3=Размер на шрифта:
|
watermark.selectText.3=Размер на шрифта:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Encripta
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Afegir Marca d'Aigua
|
watermark.title=Afegir Marca d'Aigua
|
||||||
watermark.header=Afegir Marca d'Aigua
|
watermark.header=Afegir Marca d'Aigua
|
||||||
watermark.customColor=Color de Text Personalitzat
|
|
||||||
watermark.selectText.1=Selecciona el PDF per afegir la Marca d'Aigua:
|
watermark.selectText.1=Selecciona el PDF per afegir la Marca d'Aigua:
|
||||||
watermark.selectText.2=Text de la Marca d'Aigua
|
watermark.selectText.2=Text de la Marca d'Aigua
|
||||||
watermark.selectText.3=Mida de la Font:
|
watermark.selectText.3=Mida de la Font:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Šifrovat
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Přidat vodoznak
|
watermark.title=Přidat vodoznak
|
||||||
watermark.header=Přidat vodoznak
|
watermark.header=Přidat vodoznak
|
||||||
watermark.customColor=Vlastní barva textu
|
|
||||||
watermark.selectText.1=Vyberte PDF, ke kterému chcete přidat vodoznak:
|
watermark.selectText.1=Vyberte PDF, ke kterému chcete přidat vodoznak:
|
||||||
watermark.selectText.2=Text vodoznaku:
|
watermark.selectText.2=Text vodoznaku:
|
||||||
watermark.selectText.3=Velikost písma:
|
watermark.selectText.3=Velikost písma:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Kryptér
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Tilføj Vandmærke
|
watermark.title=Tilføj Vandmærke
|
||||||
watermark.header=Tilføj Vandmærke
|
watermark.header=Tilføj Vandmærke
|
||||||
watermark.customColor=Brugerdefineret Tekstfarve
|
|
||||||
watermark.selectText.1=Vælg PDF til at tilføje vandmærke:
|
watermark.selectText.1=Vælg PDF til at tilføje vandmærke:
|
||||||
watermark.selectText.2=Vandmærketekst:
|
watermark.selectText.2=Vandmærketekst:
|
||||||
watermark.selectText.3=Skriftstørrelse:
|
watermark.selectText.3=Skriftstørrelse:
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ navbar.search=Suche
|
|||||||
navbar.sections.organize=Organisieren
|
navbar.sections.organize=Organisieren
|
||||||
navbar.sections.convertTo=In PDF konvertieren
|
navbar.sections.convertTo=In PDF konvertieren
|
||||||
navbar.sections.convertFrom=Konvertieren von PDF
|
navbar.sections.convertFrom=Konvertieren von PDF
|
||||||
navbar.sections.security=Signieren und Sicherheit
|
navbar.sections.security=Zeichen und Sicherheit
|
||||||
navbar.sections.advance=Erweiterte Funktionen
|
navbar.sections.advance=Fortschrittlich
|
||||||
navbar.sections.edit=Anzeigen und Bearbeiten
|
navbar.sections.edit=Anzeigen und Bearbeiten
|
||||||
navbar.sections.popular=Beliebt
|
navbar.sections.popular=Beliebt
|
||||||
|
|
||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Verschlüsseln
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Wasserzeichen hinzufügen
|
watermark.title=Wasserzeichen hinzufügen
|
||||||
watermark.header=Wasserzeichen hinzufügen
|
watermark.header=Wasserzeichen hinzufügen
|
||||||
watermark.customColor=Benutzerdefinierte Textfarbe
|
|
||||||
watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll:
|
watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll:
|
||||||
watermark.selectText.2=Wasserzeichen Text:
|
watermark.selectText.2=Wasserzeichen Text:
|
||||||
watermark.selectText.3=Schriftgröße:
|
watermark.selectText.3=Schriftgröße:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Κρυπτογράφηση
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Προσθήκη Υδατογραφήματος
|
watermark.title=Προσθήκη Υδατογραφήματος
|
||||||
watermark.header=Προσθήκη Υδατογραφήματος
|
watermark.header=Προσθήκη Υδατογραφήματος
|
||||||
watermark.customColor=Προσαρμοσμένο χρώμα κειμένου
|
|
||||||
watermark.selectText.1=Επιλέξτε PDF για την προσθήκη του υδατογραφήματος:
|
watermark.selectText.1=Επιλέξτε PDF για την προσθήκη του υδατογραφήματος:
|
||||||
watermark.selectText.2=Κείμενο Υδατογραφήματος:
|
watermark.selectText.2=Κείμενο Υδατογραφήματος:
|
||||||
watermark.selectText.3=Μέγεθος Κειμένου:
|
watermark.selectText.3=Μέγεθος Κειμένου:
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ home.auto-rename.title=Auto Rename PDF File
|
|||||||
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
auto-rename.tags=auto-detect,header-based,organize,relabel
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
home.adjust-contrast.title=Adjust Colours/Contrast
|
home.adjust-contrast.title=Adjust Coloors/Contrast
|
||||||
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
adjust-contrast.tags=color-correction,tune,modify,enhance,colour-correction
|
adjust-contrast.tags=color-correction,tune,modify,enhance,colour-correction
|
||||||
|
|
||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Encrypt
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Add Watermark
|
watermark.title=Add Watermark
|
||||||
watermark.header=Add Watermark
|
watermark.header=Add Watermark
|
||||||
watermark.customColor=Custom Text Colour
|
|
||||||
watermark.selectText.1=Select PDF to add watermark to:
|
watermark.selectText.1=Select PDF to add watermark to:
|
||||||
watermark.selectText.2=Watermark Text:
|
watermark.selectText.2=Watermark Text:
|
||||||
watermark.selectText.3=Font Size:
|
watermark.selectText.3=Font Size:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Encrypt
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Add Watermark
|
watermark.title=Add Watermark
|
||||||
watermark.header=Add Watermark
|
watermark.header=Add Watermark
|
||||||
watermark.customColor=Custom Text Color
|
|
||||||
watermark.selectText.1=Select PDF to add watermark to:
|
watermark.selectText.1=Select PDF to add watermark to:
|
||||||
watermark.selectText.2=Watermark Text:
|
watermark.selectText.2=Watermark Text:
|
||||||
watermark.selectText.3=Font Size:
|
watermark.selectText.3=Font Size:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Encriptar
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Añadir marca de agua
|
watermark.title=Añadir marca de agua
|
||||||
watermark.header=Añadir marca de agua
|
watermark.header=Añadir marca de agua
|
||||||
watermark.customColor=Personalizar color de texto
|
|
||||||
watermark.selectText.1=Seleccionar PDF para añadir marca de agua:
|
watermark.selectText.1=Seleccionar PDF para añadir marca de agua:
|
||||||
watermark.selectText.2=Texto de la marca de agua:
|
watermark.selectText.2=Texto de la marca de agua:
|
||||||
watermark.selectText.3=Tamaño de la Fuente:
|
watermark.selectText.3=Tamaño de la Fuente:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Enkriptatu
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Gehitu ur-marka
|
watermark.title=Gehitu ur-marka
|
||||||
watermark.header=Gehitu ur-marka
|
watermark.header=Gehitu ur-marka
|
||||||
watermark.customColor=Custom Text Color
|
|
||||||
watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko:
|
watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko:
|
||||||
watermark.selectText.2=Ur-markaren testua:
|
watermark.selectText.2=Ur-markaren testua:
|
||||||
watermark.selectText.3=Letra-tipoaren tamaina:
|
watermark.selectText.3=Letra-tipoaren tamaina:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1056,7 +1056,6 @@ addPassword.submit=Chiffrer
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Ajouter un filigrane
|
watermark.title=Ajouter un filigrane
|
||||||
watermark.header=Ajouter un filigrane
|
watermark.header=Ajouter un filigrane
|
||||||
watermark.customColor=Couleur de texte personnalisée
|
|
||||||
watermark.selectText.1=PDF auquel ajouter un filigrane
|
watermark.selectText.1=PDF auquel ajouter un filigrane
|
||||||
watermark.selectText.2=Texte du filigrane
|
watermark.selectText.2=Texte du filigrane
|
||||||
watermark.selectText.3=Taille de police
|
watermark.selectText.3=Taille de police
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Criptigh
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Cuir Uisce leis
|
watermark.title=Cuir Uisce leis
|
||||||
watermark.header=Cuir Uisce leis
|
watermark.header=Cuir Uisce leis
|
||||||
watermark.customColor=Dath Téacs Saincheaptha
|
|
||||||
watermark.selectText.1=Roghnaigh PDF chun comhartha uisce a chur leis:
|
watermark.selectText.1=Roghnaigh PDF chun comhartha uisce a chur leis:
|
||||||
watermark.selectText.2=Téacs Comhartha Uisce:
|
watermark.selectText.2=Téacs Comhartha Uisce:
|
||||||
watermark.selectText.3=Méid cló:
|
watermark.selectText.3=Méid cló:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=एन्क्रिप्ट करें
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=वॉटरमार्क जोड़ें
|
watermark.title=वॉटरमार्क जोड़ें
|
||||||
watermark.header=वॉटरमार्क जोड़ें
|
watermark.header=वॉटरमार्क जोड़ें
|
||||||
watermark.customColor=संवैधित टेक्स्ट रंग
|
|
||||||
watermark.selectText.1=वॉटरमार्क जोड़ने के लिए पीडीएफ चुनें:
|
watermark.selectText.1=वॉटरमार्क जोड़ने के लिए पीडीएफ चुनें:
|
||||||
watermark.selectText.2=वॉटरमार्क टेक्स्ट:
|
watermark.selectText.2=वॉटरमार्क टेक्स्ट:
|
||||||
watermark.selectText.3=फ़ॉन्ट साइज़:
|
watermark.selectText.3=फ़ॉन्ट साइज़:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Šifriraj
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Dodaj vodeni žig
|
watermark.title=Dodaj vodeni žig
|
||||||
watermark.header=Dodaj vodeni žig
|
watermark.header=Dodaj vodeni žig
|
||||||
watermark.customColor=Prilagođena boja teksta
|
|
||||||
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
||||||
watermark.selectText.2=Tekst vodenog žiga:
|
watermark.selectText.2=Tekst vodenog žiga:
|
||||||
watermark.selectText.3=Veličina fonta:
|
watermark.selectText.3=Veličina fonta:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Titkosítás
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Vízjel hozzáadása
|
watermark.title=Vízjel hozzáadása
|
||||||
watermark.header=Vízjel hozzáadása
|
watermark.header=Vízjel hozzáadása
|
||||||
watermark.customColor=Egyéni szövegszín
|
|
||||||
watermark.selectText.1=Válassza ki a PDF-t, amelyhez vízjelet kíván hozzáadni:
|
watermark.selectText.1=Válassza ki a PDF-t, amelyhez vízjelet kíván hozzáadni:
|
||||||
watermark.selectText.2=Vízjel szövege:
|
watermark.selectText.2=Vízjel szövege:
|
||||||
watermark.selectText.3=Betűméret:
|
watermark.selectText.3=Betűméret:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Enkripsi
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Tambahkan Watermark
|
watermark.title=Tambahkan Watermark
|
||||||
watermark.header=Tambahkan Watermark
|
watermark.header=Tambahkan Watermark
|
||||||
watermark.customColor=Warna Teks Kustom
|
|
||||||
watermark.selectText.1=Pilih PDF untuk menambahkan watermark:
|
watermark.selectText.1=Pilih PDF untuk menambahkan watermark:
|
||||||
watermark.selectText.2=Text Watermark:
|
watermark.selectText.2=Text Watermark:
|
||||||
watermark.selectText.3=Ukuran Huruf:
|
watermark.selectText.3=Ukuran Huruf:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Crittografa
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Aggiungi Filigrana
|
watermark.title=Aggiungi Filigrana
|
||||||
watermark.header=Aggiungi filigrana
|
watermark.header=Aggiungi filigrana
|
||||||
watermark.customColor=Colore testo personalizzato
|
|
||||||
watermark.selectText.1=Seleziona PDF a cui aggiungere la filigrana:
|
watermark.selectText.1=Seleziona PDF a cui aggiungere la filigrana:
|
||||||
watermark.selectText.2=Testo:
|
watermark.selectText.2=Testo:
|
||||||
watermark.selectText.3=Dimensione carattere:
|
watermark.selectText.3=Dimensione carattere:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=暗号化
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=透かしの追加
|
watermark.title=透かしの追加
|
||||||
watermark.header=透かしの追加
|
watermark.header=透かしの追加
|
||||||
watermark.customColor=文字色のカスタム
|
|
||||||
watermark.selectText.1=透かしを追加するPDFを選択:
|
watermark.selectText.1=透かしを追加するPDFを選択:
|
||||||
watermark.selectText.2=透かしのテキスト:
|
watermark.selectText.2=透かしのテキスト:
|
||||||
watermark.selectText.3=文字サイズ:
|
watermark.selectText.3=文字サイズ:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=암호화
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=워터마크 추가
|
watermark.title=워터마크 추가
|
||||||
watermark.header=워터마크 추가
|
watermark.header=워터마크 추가
|
||||||
watermark.customColor=사용자 정의 텍스트 색상
|
|
||||||
watermark.selectText.1=워터마크를 추가할 PDF 선택:
|
watermark.selectText.1=워터마크를 추가할 PDF 선택:
|
||||||
watermark.selectText.2=워터마크 텍스트:
|
watermark.selectText.2=워터마크 텍스트:
|
||||||
watermark.selectText.3=폰트 크기:
|
watermark.selectText.3=폰트 크기:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Versleutelen
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Watermerk toevoegen
|
watermark.title=Watermerk toevoegen
|
||||||
watermark.header=Watermerk toevoegen
|
watermark.header=Watermerk toevoegen
|
||||||
watermark.customColor=Aangepaste tekstkleur
|
|
||||||
watermark.selectText.1=Selecteer PDF om watermerk toe te voegen:
|
watermark.selectText.1=Selecteer PDF om watermerk toe te voegen:
|
||||||
watermark.selectText.2=Watermerk tekst:
|
watermark.selectText.2=Watermerk tekst:
|
||||||
watermark.selectText.3=Tekengrootte:
|
watermark.selectText.3=Tekengrootte:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Krypter
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Legg til vannmerke
|
watermark.title=Legg til vannmerke
|
||||||
watermark.header=Legg til vannmerke
|
watermark.header=Legg til vannmerke
|
||||||
watermark.customColor=Tilpasset Tekstfarge
|
|
||||||
watermark.selectText.1=Velg PDF-fil å legge til vannmerke på:
|
watermark.selectText.1=Velg PDF-fil å legge til vannmerke på:
|
||||||
watermark.selectText.2=Vannmerketekst:
|
watermark.selectText.2=Vannmerketekst:
|
||||||
watermark.selectText.3=Skriftstørrelse:
|
watermark.selectText.3=Skriftstørrelse:
|
||||||
|
|||||||
1
src/main/resources/messages_pl_PL.properties
Normal file → Executable file
1
src/main/resources/messages_pl_PL.properties
Normal file → Executable file
@@ -1056,7 +1056,6 @@ addPassword.submit=Zablokuj
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Dodaj znak wodny
|
watermark.title=Dodaj znak wodny
|
||||||
watermark.header=Dodaj znak wodny
|
watermark.header=Dodaj znak wodny
|
||||||
watermark.customColor=Własny kolor tekstu
|
|
||||||
watermark.selectText.1=Wybierz dokument PDF, do którego chcesz dodać znak wodny:
|
watermark.selectText.1=Wybierz dokument PDF, do którego chcesz dodać znak wodny:
|
||||||
watermark.selectText.2=Treść znaku wodnego:
|
watermark.selectText.2=Treść znaku wodnego:
|
||||||
watermark.selectText.3=Rozmiar czcionki:
|
watermark.selectText.3=Rozmiar czcionki:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Criptografar
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Adicionar marca d'água
|
watermark.title=Adicionar marca d'água
|
||||||
watermark.header=Adicionar marca d'água
|
watermark.header=Adicionar marca d'água
|
||||||
watermark.customColor=Cor de texto personalizada
|
|
||||||
watermark.selectText.1=Selecione PDF para adicionar a marca d'água:
|
watermark.selectText.1=Selecione PDF para adicionar a marca d'água:
|
||||||
watermark.selectText.2=Texto da marca d'água:
|
watermark.selectText.2=Texto da marca d'água:
|
||||||
watermark.selectText.3=Tamanho da fonte:
|
watermark.selectText.3=Tamanho da fonte:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Proteger
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Adicionar Marca d'Água
|
watermark.title=Adicionar Marca d'Água
|
||||||
watermark.header=Adicionar Marca d'Água
|
watermark.header=Adicionar Marca d'Água
|
||||||
watermark.customColor=Personalizar a cor do texto
|
|
||||||
watermark.selectText.1=Seleccione o PDF para Adicionar a Marca d'Água
|
watermark.selectText.1=Seleccione o PDF para Adicionar a Marca d'Água
|
||||||
watermark.selectText.2=Texto da Marca d'Água
|
watermark.selectText.2=Texto da Marca d'Água
|
||||||
watermark.selectText.3=Tamanho da Fonte
|
watermark.selectText.3=Tamanho da Fonte
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Criptează
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Adaugă Filigran
|
watermark.title=Adaugă Filigran
|
||||||
watermark.header=Adaugă Filigran
|
watermark.header=Adaugă Filigran
|
||||||
watermark.customColor=Culoare Text Personalizată
|
|
||||||
watermark.selectText.1=Selectează PDF-ul la care să adaugi filigranul:
|
watermark.selectText.1=Selectează PDF-ul la care să adaugi filigranul:
|
||||||
watermark.selectText.2=Textul Filigranului:
|
watermark.selectText.2=Textul Filigranului:
|
||||||
watermark.selectText.3=Mărimea fontului:
|
watermark.selectText.3=Mărimea fontului:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Шифровать
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Добавить водяной знак
|
watermark.title=Добавить водяной знак
|
||||||
watermark.header=Добавить водяной знак
|
watermark.header=Добавить водяной знак
|
||||||
watermark.customColor=Настроенный цвет текста
|
|
||||||
watermark.selectText.1=Выберите PDF, чтобы добавить водяной знак:
|
watermark.selectText.1=Выберите PDF, чтобы добавить водяной знак:
|
||||||
watermark.selectText.2=Текст водяного знака:
|
watermark.selectText.2=Текст водяного знака:
|
||||||
watermark.selectText.3=Размер шрифта:
|
watermark.selectText.3=Размер шрифта:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Zašifrovať
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Pridať vodotlač
|
watermark.title=Pridať vodotlač
|
||||||
watermark.header=Pridať vodotlač
|
watermark.header=Pridať vodotlač
|
||||||
watermark.customColor=Vlastná farba textu
|
|
||||||
watermark.selectText.1=Vyberte PDF, do ktorého chcete pridať vodotlač:
|
watermark.selectText.1=Vyberte PDF, do ktorého chcete pridať vodotlač:
|
||||||
watermark.selectText.2=Text vodotlače:
|
watermark.selectText.2=Text vodotlače:
|
||||||
watermark.selectText.3=Veľkosť písma:
|
watermark.selectText.3=Veľkosť písma:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Enkriptuj
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Dodaj vodeni žig
|
watermark.title=Dodaj vodeni žig
|
||||||
watermark.header=Dodaj vodeni žig
|
watermark.header=Dodaj vodeni žig
|
||||||
watermark.customColor=Custom Text Color
|
|
||||||
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
|
||||||
watermark.selectText.2=Tekst vodenog žiga:
|
watermark.selectText.2=Tekst vodenog žiga:
|
||||||
watermark.selectText.3=Veličina fonta:
|
watermark.selectText.3=Veličina fonta:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Kryptera
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Lägg till vattenstämpel
|
watermark.title=Lägg till vattenstämpel
|
||||||
watermark.header=Lägg till vattenstämpel
|
watermark.header=Lägg till vattenstämpel
|
||||||
watermark.customColor=Anpassad textfärg
|
|
||||||
watermark.selectText.1=Välj PDF för att lägga till vattenstämpel till:
|
watermark.selectText.1=Välj PDF för att lägga till vattenstämpel till:
|
||||||
watermark.selectText.2=Vattenmärkestext:
|
watermark.selectText.2=Vattenmärkestext:
|
||||||
watermark.selectText.3=Teckenstorlek:
|
watermark.selectText.3=Teckenstorlek:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=เข้ารหัส
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=เพิ่มลายน้ำ
|
watermark.title=เพิ่มลายน้ำ
|
||||||
watermark.header=เพิ่มลายน้ำ
|
watermark.header=เพิ่มลายน้ำ
|
||||||
watermark.customColor=สีข้อความที่กำหนดเอง
|
|
||||||
watermark.selectText.1=เลือก PDF เพื่อเพิ่มลายน้ำ:
|
watermark.selectText.1=เลือก PDF เพื่อเพิ่มลายน้ำ:
|
||||||
watermark.selectText.2=ข้อความลายน้ำ:
|
watermark.selectText.2=ข้อความลายน้ำ:
|
||||||
watermark.selectText.3=ขนาดฟอนต์:
|
watermark.selectText.3=ขนาดฟอนต์:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Şifrele
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Filigran Ekle
|
watermark.title=Filigran Ekle
|
||||||
watermark.header=Filigran Ekle
|
watermark.header=Filigran Ekle
|
||||||
watermark.customColor=Özel Metin Rengi
|
|
||||||
watermark.selectText.1=Filigran eklemek için PDF seçin:
|
watermark.selectText.1=Filigran eklemek için PDF seçin:
|
||||||
watermark.selectText.2=Filigran Metni:
|
watermark.selectText.2=Filigran Metni:
|
||||||
watermark.selectText.3=Yazı Boyutu:
|
watermark.selectText.3=Yazı Boyutu:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Шифрувати
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Додати водяний знак
|
watermark.title=Додати водяний знак
|
||||||
watermark.header=Додати водяний знак
|
watermark.header=Додати водяний знак
|
||||||
watermark.customColor=Користувацький колір тексту
|
|
||||||
watermark.selectText.1=Виберіть PDF, щоб додати водяний знак:
|
watermark.selectText.1=Виберіть PDF, щоб додати водяний знак:
|
||||||
watermark.selectText.2=Текст водяного знаку:
|
watermark.selectText.2=Текст водяного знаку:
|
||||||
watermark.selectText.3=Розмір шрифту:
|
watermark.selectText.3=Розмір шрифту:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=Mã hóa
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=Thêm hình mờ
|
watermark.title=Thêm hình mờ
|
||||||
watermark.header=Thêm hình mờ
|
watermark.header=Thêm hình mờ
|
||||||
watermark.customColor=Màu văn bản tùy chỉnh
|
|
||||||
watermark.selectText.1=Chọn PDF để thêm hình mờ:
|
watermark.selectText.1=Chọn PDF để thêm hình mờ:
|
||||||
watermark.selectText.2=Văn bản hình mờ:
|
watermark.selectText.2=Văn bản hình mờ:
|
||||||
watermark.selectText.3=Cỡ chữ:
|
watermark.selectText.3=Cỡ chữ:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=加密
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=添加水印
|
watermark.title=添加水印
|
||||||
watermark.header=添加水印
|
watermark.header=添加水印
|
||||||
watermark.customColor=自定义文本颜色
|
|
||||||
watermark.selectText.1=选择要添加水印的PDF:
|
watermark.selectText.1=选择要添加水印的PDF:
|
||||||
watermark.selectText.2=水印文本:
|
watermark.selectText.2=水印文本:
|
||||||
watermark.selectText.3=字体大小:
|
watermark.selectText.3=字体大小:
|
||||||
|
|||||||
@@ -1056,7 +1056,6 @@ addPassword.submit=加密
|
|||||||
#watermark
|
#watermark
|
||||||
watermark.title=新增浮水印
|
watermark.title=新增浮水印
|
||||||
watermark.header=新增浮水印
|
watermark.header=新增浮水印
|
||||||
watermark.customColor=自訂文字顏色
|
|
||||||
watermark.selectText.1=選擇要新增浮水印的 PDF:
|
watermark.selectText.1=選擇要新增浮水印的 PDF:
|
||||||
watermark.selectText.2=浮水印文字:
|
watermark.selectText.2=浮水印文字:
|
||||||
watermark.selectText.3=字型大小:
|
watermark.selectText.3=字型大小:
|
||||||
|
|||||||
@@ -1,219 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ir" viewBox="0 0 640 480">
|
|
||||||
<defs>
|
|
||||||
<clipPath id="ir-a">
|
|
||||||
<path fill-opacity=".7" d="M-85.3 0h682.7v512H-85.3z"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
<g fill-rule="evenodd" clip-path="url(#ir-a)" transform="translate(80)scale(.9375)">
|
|
||||||
<path fill="#fff" d="M-192 0h896v512h-896z"/>
|
|
||||||
<path fill="#da0000" d="M-192 343.8h896V512h-896z"/>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M-21.6 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M52.4 367.7v3.4H33.8v-3.4zm-34.6-7.9H21v11.3h-3.3z"/>
|
|
||||||
<path d="M49.6 351H53v20h-3.4zm-8.4 0h3.3v20h-3.3zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M17.8 359.9H21V371h-3.3z"/>
|
|
||||||
<path d="M17.8 359.9H21V371h-3.3z"/>
|
|
||||||
<path d="M17.8 359.9H21V371h-3.3zm-39.3 0h3.3V371h-3.3zm28.8 0h3.4V371H7.3zm-14.3 0h3.4V371H-7z"/>
|
|
||||||
<path d="M9.6 367.7v3.4H-5.5v-3.4zm1-8.7v3.4H1V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M-102.2 351h49v3.3h-49zm7.3 16.8h3.4v3.3H-95zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M-28.2 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M-31 351h3.4v20H-31zm-8.4 0h3.3v20h-3.3zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M-62.8 359.9h3.3V371h-3.3z"/>
|
|
||||||
<path d="M-62.8 359.9h3.3V371h-3.3z"/>
|
|
||||||
<path d="M-62.8 359.9h3.3V371h-3.3zm-39.3 0h3.3V371h-3.3zm28.8 0h3.3V371h-3.3zm-14.3 0h3.4V371h-3.4z"/>
|
|
||||||
<path d="M-71 367.7v3.4h-15v-3.4zm1-8.7v3.4h-9.6V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M58.3 351h49v3.3h-49zm7.3 16.8H69v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.3-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M132.3 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M129.5 351h3.4v20h-3.4zm-8.4 0h3.4v20H121zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M97.7 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M97.7 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M97.7 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
|
|
||||||
<path d="M89.6 367.7v3.4H74.4v-3.4zm1-8.7v3.4H81V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M622.7 351h49v3.3h-49zm7.3 16.8h3.4v3.3H630zm41.9 0v3.3H662v-3.4zm5.3-16.8h3.3v20h-3.4z"/>
|
|
||||||
<path d="M696.7 367.7v3.4H678v-3.4zm-34.6-7.9h3.4v11.3H662z"/>
|
|
||||||
<path d="M694 351h3.3v20h-3.4zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M662 359.9h3.5V371H662z"/>
|
|
||||||
<path d="M662 359.9h3.5V371H662z"/>
|
|
||||||
<path d="M662 359.9h3.5V371H662zm-39.2 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
|
|
||||||
<path d="M654 367.7v3.4h-15.2v-3.4zm1-8.7v3.4h-9.6V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M138.7 351h49.1v3.3h-49zm7.4 16.8h3.3v3.3h-3.3zm41.8 0v3.3h-9.8v-3.4zm5.3-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M212.8 367.7v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M210 351h3.4v20H210zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-17.9V359zm39.3 0v3.4h-17.9V359z"/>
|
|
||||||
<path d="M178.1 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M178.1 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M178.1 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.2 0h3.3V371h-3.3z"/>
|
|
||||||
<path d="M170 367.7v3.4h-15.1v-3.4zm1-8.7v3.4h-9.6V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M219.5 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zM274 351h3.3v20H274z"/>
|
|
||||||
<path d="M293.5 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M290.7 351h3.4v20h-3.4zm-8.4 0h3.4v20h-3.4zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M258.9 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M258.9 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M258.9 359.9h3.4V371h-3.4zm-39.3 0h3.3V371h-3.3zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371H234z"/>
|
|
||||||
<path d="M250.8 367.7v3.4h-15.2v-3.4zm1-8.7v3.4H242V359z"/>
|
|
||||||
</g>
|
|
||||||
<path fill="#239f40" d="M-192 0h896v168.2h-896z"/>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M300.7 351h49v3.3h-49zm7.3 16.8h3.4v3.3H308zm41.9 0v3.3H340v-3.4zm5.3-16.8h3.3v20h-3.3z"/>
|
|
||||||
<path d="M374.7 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3H340z"/>
|
|
||||||
<path d="M372 351h3.3v20H372zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M340 359.9h3.5V371H340z"/>
|
|
||||||
<path d="M340 359.9h3.5V371H340z"/>
|
|
||||||
<path d="M340 359.9h3.5V371H340zm-39.2 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
|
|
||||||
<path d="M332 367.7v3.4h-15.2v-3.4zm1-8.7v3.4h-9.6V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M381.4 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm42 0v3.3h-9.9v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M455.4 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M452.7 351h3.3v20h-3.3zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-17.9V359zm39.3 0v3.4h-17.9V359z"/>
|
|
||||||
<path d="M420.8 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M420.8 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M420.8 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.3z"/>
|
|
||||||
<path d="M412.7 367.7v3.4h-15.1v-3.4zm1-8.7v3.4H404V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M462.2 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M536.2 367.7v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M533.4 351h3.4v20h-3.4zm-8.4 0h3.3v20H525zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M501.6 359.9h3.3V371h-3.3z"/>
|
|
||||||
<path d="M501.6 359.9h3.3V371h-3.3z"/>
|
|
||||||
<path d="M501.6 359.9h3.3V371h-3.3zm-39.4 0h3.4V371h-3.4zm28.9 0h3.3V371h-3.3zm-14.3 0h3.4V371h-3.4z"/>
|
|
||||||
<path d="M493.4 367.7v3.4h-15.1v-3.4zm1-8.7v3.4h-9.6V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M543.4 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M617.4 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M614.6 351h3.4v20h-3.4zm-8.4 0h3.3v20h-3.3zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
|
|
||||||
<path d="M582.8 359.9h3.3V371h-3.3z"/>
|
|
||||||
<path d="M582.8 359.9h3.3V371h-3.3z"/>
|
|
||||||
<path d="M582.8 359.9h3.3V371h-3.3zm-39.3 0h3.3V371h-3.3zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371H558z"/>
|
|
||||||
<path d="M574.6 367.7v3.4h-15.1v-3.4zm1-8.7v3.4H566V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M-183.8 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm42 0v3.3h-9.9v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
|
|
||||||
<path d="M-109.8 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M-112.5 351h3.3v20h-3.3zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-17.9V359zm39.3 0v3.4h-17.9V359z"/>
|
|
||||||
<path d="M-144.4 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M-144.4 359.9h3.4V371h-3.4z"/>
|
|
||||||
<path d="M-144.4 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
|
|
||||||
<path d="M-152.5 367.7v3.4h-15.2v-3.4zm1-8.7v3.4h-9.6V359z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M-21.6 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M52.4 160.2v3.4H33.8v-3.4zm-34.6-7.9H21v11.3h-3.3z"/>
|
|
||||||
<path d="M49.6 143.4H53v20.2h-3.4zm-8.4 0h3.3v20.2h-3.3zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M17.8 152.3H21v11.3h-3.3z"/>
|
|
||||||
<path d="M17.8 152.3H21v11.3h-3.3z"/>
|
|
||||||
<path d="M17.8 152.3H21v11.3h-3.3zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.4v11.3H7.3zm-14.3 0h3.4v11.3H-7z"/>
|
|
||||||
<path d="M9.6 160.2v3.4H-5.5v-3.4zm1-8.7v3.3H1v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M-102.2 143.4h49v3.4h-49zm7.3 17h3.4v3.2H-95zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M-28.2 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M-31 143.4h3.4v20.2H-31zm-8.4 0h3.3v20.2h-3.3zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M-62.8 152.3h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M-62.8 152.3h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M-62.8 152.3h3.3v11.3h-3.3zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.3v11.3h-3.3zm-14.3 0h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M-71 160.2v3.4h-15v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M58.3 143.4h49v3.4h-49zm7.3 17H69v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.3-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M132.3 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M129.5 143.4h3.4v20.2h-3.4zm-8.4 0h3.4v20.2H121zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M97.7 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M97.7 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M97.7 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M89.6 160.2v3.4H74.4v-3.4zm1-8.7v3.3H81v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M622.7 143.4h49v3.4h-49zm7.3 17h3.4v3.2H630zm41.9-.2v3.4H662v-3.4zm5.3-16.8h3.3v20.2h-3.4z"/>
|
|
||||||
<path d="M696.7 160.2v3.4H678v-3.4zm-34.6-7.9h3.4v11.3H662z"/>
|
|
||||||
<path d="M694 143.4h3.3v20.2h-3.4zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M662 152.3h3.5v11.3H662z"/>
|
|
||||||
<path d="M662 152.3h3.5v11.3H662z"/>
|
|
||||||
<path d="M662 152.3h3.5v11.3H662zm-39.2 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M654 160.2v3.4h-15.2v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M138.7 143.4h49.1v3.4h-49zm7.4 17h3.3v3.2h-3.3zm41.8-.2v3.4h-9.8v-3.4zm5.3-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M212.8 160.2v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M210 143.4h3.4v20.2H210zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-17.9v-3.3zm39.3 0v3.4h-17.9v-3.3z"/>
|
|
||||||
<path d="M178.1 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M178.1 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M178.1 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.2 0h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M170 160.2v3.4h-15.1v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M219.5 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.3-16.8h3.3v20.2H274z"/>
|
|
||||||
<path d="M293.5 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M290.7 143.4h3.4v20.2h-3.4zm-8.4 0h3.4v20.2h-3.4zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M258.9 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M258.9 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M258.9 152.3h3.4v11.3h-3.4zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3H234z"/>
|
|
||||||
<path d="M250.8 160.2v3.4h-15.2v-3.4zm1-8.7v3.3H242v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M300.7 143.4h49v3.4h-49zm7.3 17h3.4v3.2H308zm41.9-.2v3.4H340v-3.4zm5.3-16.8h3.3v20.2h-3.3z"/>
|
|
||||||
<path d="M374.7 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3H340z"/>
|
|
||||||
<path d="M372 143.4h3.3v20.2H372zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M340 152.3h3.5v11.3H340z"/>
|
|
||||||
<path d="M340 152.3h3.5v11.3H340z"/>
|
|
||||||
<path d="M340 152.3h3.5v11.3H340zm-39.2 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M332 160.2v3.4h-15.2v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M381.4 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm42-.2v3.4h-9.9v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M455.4 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M452.7 143.4h3.3v20.2h-3.3zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-17.9v-3.3zm39.3 0v3.4h-17.9v-3.3z"/>
|
|
||||||
<path d="M420.8 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M420.8 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M420.8 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.3z"/>
|
|
||||||
<path d="M412.7 160.2v3.4h-15.1v-3.4zm1-8.7v3.3H404v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M462.2 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M536.2 160.2v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M533.4 143.4h3.4v20.2h-3.4zm-8.4 0h3.3v20.2H525zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M501.6 152.3h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M501.6 152.3h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M501.6 152.3h3.3v11.3h-3.3zm-39.4 0h3.4v11.3h-3.4zm28.9 0h3.3v11.3h-3.3zm-14.3 0h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M493.4 160.2v3.4h-15.1v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M543.4 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M617.4 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M614.6 143.4h3.4v20.2h-3.4zm-8.4 0h3.3v20.2h-3.3zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
|
|
||||||
<path d="M582.8 152.3h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M582.8 152.3h3.3v11.3h-3.3z"/>
|
|
||||||
<path d="M582.8 152.3h3.3v11.3h-3.3zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3H558z"/>
|
|
||||||
<path d="M574.6 160.2v3.4h-15.1v-3.4zm1-8.7v3.3H566v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<g fill="#fff" stroke-width="1pt">
|
|
||||||
<path d="M-183.8 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm42-.2v3.4h-9.9v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
|
|
||||||
<path d="M-109.8 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M-112.5 143.4h3.3v20.2h-3.3zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-17.9v-3.3zm39.3 0v3.4h-17.9v-3.3z"/>
|
|
||||||
<path d="M-144.4 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M-144.4 152.3h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M-144.4 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
|
|
||||||
<path d="M-152.5 160.2v3.4h-15.2v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
|
|
||||||
</g>
|
|
||||||
<path fill="#d90000" d="M-68.8 339.5h6V350h-6zm160.5 0h6V350h-6zm-283.7 0h6V350h-6zm81.5 0h6V350h-6zm80.9 0h6V350h-6zm40 0h6V350h-6zm40.9 0h6V350h-6zm80.4 0h6V350h-6zm203 0h6.1V350h-6zm-162.1 0h6V350h-6zm40 0h6V350h-6zm40.5 0h6V350h-6zm40.4 0h6V350h-6zm323.2 0h6V350h-6zm-242.7 0h6V350h-6zm40.8 0h6V350h-6zm41.3 0h6V350h-6zm38.8 0h6V350h-6zm41.3 0h6V350h-6zm40.4 0h6V350h-6zm119.7 0h6V350h-6zm-38.8 0h6V350h-6zm-808.9 0h6V350h-6z"/>
|
|
||||||
<path fill="#239e3f" d="M-68.8 162.6h6v10.5h-6zm160.5 0h6v10.5h-6zm-283.7 0h6v10.5h-6zm81.5 0h6v10.5h-6zm80.9 0h6v10.5h-6zm40 0h6v10.5h-6zm40.9 0h6v10.5h-6zm80.4 0h6v10.5h-6zm203 0h6.1v10.5h-6zm-162.1 0h6v10.5h-6zm40 0h6v10.5h-6zm40.5 0h6v10.5h-6zm40.4 0h6v10.5h-6zm323.2 0h6v10.5h-6zm-242.7 0h6v10.5h-6zm40.8 0h6v10.5h-6zm41.3 0h6v10.5h-6zm38.8 0h6v10.5h-6zm41.3 0h6v10.5h-6zm40.4 0h6v10.5h-6zm119.7 0h6v10.5h-6zm-38.8 0h6v10.5h-6zm-808.9 0h6v10.5h-6z"/>
|
|
||||||
<g fill="#da0000">
|
|
||||||
<path d="M279.8 197.5c8.4 10.4 34.5 67.6-15.7 105.2-23.7 17.8-9 18.6-8.3 21.6 38-20.1 50.3-47.5 50-72-.2-24.4-13.2-46-26-54.8"/>
|
|
||||||
<path d="M284.8 194.8a73.3 73.3 0 0 1 15.7 112.4c27.2-6 62-86.4-15.7-112.4m-57.6 0a73.3 73.3 0 0 0-15.6 112.4c-27.3-6-62-86.4 15.6-112.4"/>
|
|
||||||
<path d="M232.2 197.5c-8.4 10.4-34.5 67.6 15.7 105.2 23.6 17.8 9 18.6 8.3 21.6-38-20.1-50.3-47.5-50-72 .2-24.4 13.2-46 26-54.8"/>
|
|
||||||
<path d="M304.2 319.1c-14.9.2-33.6-2-47.5-9.3 2.3 4.5 4.2 7.3 6.5 11.7 13.2 1.3 31.5 2.8 41-2.4m-95 0c14.9.2 33.6-2 47.5-9.3-2.3 4.5-4.2 7.3-6.5 11.7-13.2 1.3-31.5 2.8-41-2.4m27.3-138.7c3 8 10.9 9.2 19.3 4.5 6.2 3.6 15.7 3.9 19-4.1 2.5 19.8-18.3 15-19 11.2-7.8 7.5-22.2 3.2-19.3-11.6"/>
|
|
||||||
<path d="m256.4 331.6 7.8-9 1.1-120.1-9.3-8.2-9.3 7.8 1.9 121z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -16,7 +16,6 @@
|
|||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ga_IE"> <img th:src="@{'/images/flags/ie.svg'}" alt="icon" width="20" height="15"> Irish</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ga_IE"> <img th:src="@{'/images/flags/ie.svg'}" alt="icon" width="20" height="15"> Irish</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="it_IT"> <img th:src="@{'/images/flags/it.svg'}" alt="icon" width="20" height="15"> Italiano</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="it_IT"> <img th:src="@{'/images/flags/it.svg'}" alt="icon" width="20" height="15"> Italiano</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL"> <img th:src="@{'/images/flags/nl.svg'}" alt="icon" width="20" height="15"> Nederlands</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL"> <img th:src="@{'/images/flags/nl.svg'}" alt="icon" width="20" height="15"> Nederlands</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="fa_IR"> <img th:src="@{'/images/flags/ir.svg'}" alt="icon" width="20" height="15"> پارسی</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL"> <img th:src="@{'/images/flags/pl.svg'}" alt="icon" width="20" height="15"> Polski</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL"> <img th:src="@{'/images/flags/pl.svg'}" alt="icon" width="20" height="15"> Polski</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_BR"> <img th:src="@{'/images/flags/pt_br.svg'}" alt="icon" width="20" height="15"> Português (BR)</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_BR"> <img th:src="@{'/images/flags/pt_br.svg'}" alt="icon" width="20" height="15"> Português (BR)</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_PT"> <img th:src="@{'/images/flags/pt_pt.svg'}" alt="icon" width="20" height="15"> Português (PT)</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_PT"> <img th:src="@{'/images/flags/pt_pt.svg'}" alt="icon" width="20" height="15"> Português (PT)</a>
|
||||||
|
|||||||
@@ -92,48 +92,26 @@
|
|||||||
appendPercentageSymbol();
|
appendPercentageSymbol();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="rotation" th:text="#{watermark.selectText.4}"></label>
|
<label for="rotation" th:text="#{watermark.selectText.4}"></label>
|
||||||
<input type="text" id="rotation" name="rotation" class="form-control" value="45">
|
<input type="text" id="rotation" name="rotation" class="form-control" value="45">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="widthSpacer" th:text="#{watermark.selectText.5}"></label>
|
<label for="widthSpacer" th:text="#{watermark.selectText.5}"></label>
|
||||||
<input type="text" id="widthSpacer" name="widthSpacer" class="form-control" value="50">
|
<input type="text" id="widthSpacer" name="widthSpacer" class="form-control" value="50">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="heightSpacer" th:text="#{watermark.selectText.6}"></label>
|
<label for="heightSpacer" th:text="#{watermark.selectText.6}"></label>
|
||||||
<input type="text" id="heightSpacer" name="heightSpacer" class="form-control" value="50">
|
<input type="text" id="heightSpacer" name="heightSpacer" class="form-control" value="50">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3 form-check">
|
||||||
<label for="customColor" class="form-label" th:text="#{watermark.customColor}">Custom
|
<input type="checkbox" id="convertPDFToImage" name="convertPDFToImage">
|
||||||
Color</label>
|
<label for="convertPDFToImage" th:text="#{watermark.selectText.10}"></label>
|
||||||
<div class="form-control form-control-color" style="background-color: #d3d3d3;">
|
</div>
|
||||||
<input type="color" id="customColor" name="customColor" value="#d3d3d3">
|
<div class="mb-3 text-left">
|
||||||
</div>
|
<input type="submit" id="submitBtn" th:value="#{watermark.submit}" class="btn btn-primary">
|
||||||
<script>
|
</div>
|
||||||
let colorInput = document.getElementById("customColor");
|
</form>
|
||||||
if (colorInput) {
|
|
||||||
let colorInputContainer = colorInput.parentElement;
|
|
||||||
if (colorInputContainer) {
|
|
||||||
colorInput.onchange = function() {
|
|
||||||
colorInputContainer.style.backgroundColor = colorInput.value;
|
|
||||||
}
|
|
||||||
colorInputContainer.style.backgroundColor = colorInput.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
|
||||||
<input type="checkbox" id="convertPDFToImage" name="convertPDFToImage">
|
|
||||||
<label for="convertPDFToImage" th:text="#{watermark.selectText.10}"></label>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3 text-left">
|
|
||||||
<input type="submit" id="submitBtn" th:value="#{watermark.submit}" class="btn btn-primary">
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function toggleFileOption() {
|
function toggleFileOption() {
|
||||||
|
|||||||
BIN
src/main/resources/tl12.acrobatsecuritysettings
Normal file
BIN
src/main/resources/tl12.acrobatsecuritysettings
Normal file
Binary file not shown.
Reference in New Issue
Block a user