Compare commits
178 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c57b308909 | ||
|
|
6409274f83 | ||
|
|
bc534c12a5 | ||
|
|
b58fd2022a | ||
|
|
d850d026ed | ||
|
|
83627686d4 | ||
|
|
4e7d01c72c | ||
|
|
0f8ab20db7 | ||
|
|
88cc90786d | ||
|
|
fb66717b43 | ||
|
|
1d60433fcf | ||
|
|
0f3df6e92b | ||
|
|
ca7c63c7d7 | ||
|
|
135f9611df | ||
|
|
cfaaeebd4a | ||
|
|
09a0779180 | ||
|
|
7f7d09bc85 | ||
|
|
0c454a08dc | ||
|
|
d749b63549 | ||
|
|
2053a6950d | ||
|
|
41bd801e0d | ||
|
|
cd0e1a3962 | ||
|
|
7c2f482b3b | ||
|
|
7741d60afd | ||
|
|
8aac0c0327 | ||
|
|
7c26c56210 | ||
|
|
e88a780efe | ||
|
|
363fb5dc02 | ||
|
|
39a187b6da | ||
|
|
b4cc34a522 | ||
|
|
af94ef3d49 | ||
|
|
505855a53c | ||
|
|
87ac245341 | ||
|
|
1670a09d04 | ||
|
|
620b954336 | ||
|
|
cfd51e9b84 | ||
|
|
6c797f8216 | ||
|
|
40e208152a | ||
|
|
cf7bfa62ef | ||
|
|
a1086b9a04 | ||
|
|
9bc4bbd2c8 | ||
|
|
73156012e9 | ||
|
|
91cc3d77d4 | ||
|
|
3fc55a9e9f | ||
|
|
b666aa3f26 | ||
|
|
53e7dbe12f | ||
|
|
9d8ff6856b | ||
|
|
3fb38376b0 | ||
|
|
15c73d9dd3 | ||
|
|
86f71ffb93 | ||
|
|
eb928d3369 | ||
|
|
d7307665b3 | ||
|
|
2836f0ab5a | ||
|
|
91b7f3980c | ||
|
|
5053432c2d | ||
|
|
563c612395 | ||
|
|
95dced6455 | ||
|
|
989f0bbbfb | ||
|
|
e5eec28bfd | ||
|
|
bfc402f307 | ||
|
|
35a998b934 | ||
|
|
cadc8e499d | ||
|
|
7f7ea6da9f | ||
|
|
ab9a22d8e7 | ||
|
|
cd2728105e | ||
|
|
d75e84bdff | ||
|
|
e791fee38b | ||
|
|
ad5f057733 | ||
|
|
6f325b5fdb | ||
|
|
b73aeee18d | ||
|
|
8a54035a9f | ||
|
|
af28e30e4c | ||
|
|
492513306c | ||
|
|
bc554ff4a7 | ||
|
|
b7a0d1ece8 | ||
|
|
ca384218dc | ||
|
|
e9550fd6b2 | ||
|
|
232a305d51 | ||
|
|
a6ab448eeb | ||
|
|
f9aa157c6c | ||
|
|
b7df24acaa | ||
|
|
ad4ca1b2d7 | ||
|
|
c562d197e7 | ||
|
|
83ba1899b7 | ||
|
|
3420adc7c9 | ||
|
|
fd39f28e46 | ||
|
|
710125852a | ||
|
|
e8ec208390 | ||
|
|
4584562607 | ||
|
|
2c1412a088 | ||
|
|
0a65382979 | ||
|
|
4f404f66e5 | ||
|
|
89505ada00 | ||
|
|
374a30ac5a | ||
|
|
cee4ee4128 | ||
|
|
58fc5e2ffa | ||
|
|
951ea43f8b | ||
|
|
ca16ecef24 | ||
|
|
bb025dc2a1 | ||
|
|
d797169bd0 | ||
|
|
891f9e2252 | ||
|
|
4a579c00ce | ||
|
|
9cb4d8e088 | ||
|
|
5d3ee7755a | ||
|
|
c047c46587 | ||
|
|
54f53be5b5 | ||
|
|
8bb9e5b22f | ||
|
|
379791a326 | ||
|
|
38ec68b303 | ||
|
|
a5095b04ad | ||
|
|
a27ddb40be | ||
|
|
bc36be8a5e | ||
|
|
1e35556034 | ||
|
|
882cd41d4b | ||
|
|
724fb4bf8f | ||
|
|
b07437dbfa | ||
|
|
96f05cd518 | ||
|
|
77411e94a4 | ||
|
|
0da9c62ef8 | ||
|
|
52a7885f3c | ||
|
|
f98f089d63 | ||
|
|
6b618f3abe | ||
|
|
0732ffa76e | ||
|
|
b5b4636e56 | ||
|
|
ca12d040e1 | ||
|
|
3388b9fafa | ||
|
|
954b36e14c | ||
|
|
4d43814220 | ||
|
|
f6262c82e1 | ||
|
|
7ead12922f | ||
|
|
33a6a7869c | ||
|
|
bf995f989c | ||
|
|
21de6c6520 | ||
|
|
c14aa6851e | ||
|
|
8260eced2d | ||
|
|
d028465dc5 | ||
|
|
29dab5e47d | ||
|
|
9e655631b4 | ||
|
|
179c7b80bb | ||
|
|
349bf29122 | ||
|
|
295357f12b | ||
|
|
940f8d999e | ||
|
|
5605d53a5f | ||
|
|
116d103119 | ||
|
|
2fd8c643af | ||
|
|
4367ae7934 | ||
|
|
749461334d | ||
|
|
e83a027023 | ||
|
|
1883b477a3 | ||
|
|
37e2cd40da | ||
|
|
81a9329975 | ||
|
|
0eb019fc3c | ||
|
|
4129c75475 | ||
|
|
3d66f03f58 | ||
|
|
7b83104fd6 | ||
|
|
794aede27f | ||
|
|
08eb39b206 | ||
|
|
2566c7f3d7 | ||
|
|
a8522bb3b5 | ||
|
|
92b9142902 | ||
|
|
d07e3e6522 | ||
|
|
29aabdfba8 | ||
|
|
9af1b0cfdc | ||
|
|
6e32c7fe85 | ||
|
|
ddf5915c6a | ||
|
|
cdbf1fa73a | ||
|
|
5d926b022b | ||
|
|
50bcca10e2 | ||
|
|
a5528c06ee | ||
|
|
94526de04b | ||
|
|
1ddf7abe6f | ||
|
|
a742c1b034 | ||
|
|
6e726ac2a6 | ||
|
|
5877b40be5 | ||
|
|
a3c7f5aa46 | ||
|
|
4e28bf03bd | ||
|
|
f92482d89e | ||
|
|
3c54429fe0 |
6
.github/workflows/push-docker.yml
vendored
6
.github/workflows/push-docker.yml
vendored
@@ -21,6 +21,8 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
- uses: gradle/gradle-build-action@v2.4.2
|
- uses: gradle/gradle-build-action@v2.4.2
|
||||||
|
env:
|
||||||
|
DOCKER_ENABLE_SECURITY: false
|
||||||
with:
|
with:
|
||||||
gradle-version: 7.6
|
gradle-version: 7.6
|
||||||
arguments: clean build
|
arguments: clean build
|
||||||
@@ -77,6 +79,8 @@ jobs:
|
|||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args:
|
||||||
|
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
|
|
||||||
|
|
||||||
@@ -105,6 +109,8 @@ jobs:
|
|||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
tags: ${{ steps.meta2.outputs.tags }}
|
tags: ${{ steps.meta2.outputs.tags }}
|
||||||
labels: ${{ steps.meta2.outputs.labels }}
|
labels: ${{ steps.meta2.outputs.labels }}
|
||||||
|
build-args:
|
||||||
|
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
22
.github/workflows/releaseArtifacts.yml
vendored
22
.github/workflows/releaseArtifacts.yml
vendored
@@ -1,10 +1,20 @@
|
|||||||
name: Release Artifacts
|
name: Release Artifacts
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
enable_security: [true, false]
|
||||||
|
include:
|
||||||
|
- enable_security: true
|
||||||
|
file_suffix: '-with-login'
|
||||||
|
- enable_security: false
|
||||||
|
file_suffix: ''
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3.5.2
|
- uses: actions/checkout@v3.5.2
|
||||||
|
|
||||||
@@ -17,15 +27,17 @@ jobs:
|
|||||||
- name: Grant execute permission for gradlew
|
- name: Grant execute permission for gradlew
|
||||||
run: chmod +x gradlew
|
run: chmod +x gradlew
|
||||||
|
|
||||||
- name: Generate jar
|
- name: Generate jar (With Security=${{ matrix.enable_security }})
|
||||||
run: ./gradlew clean createExe
|
run: ./gradlew clean createExe
|
||||||
|
env:
|
||||||
|
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
|
||||||
|
|
||||||
- name: Upload binaries to release
|
- name: Upload binaries to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: ./build/launch4j/Stirling-PDF.exe
|
file: ./build/launch4j/Stirling-PDF.exe
|
||||||
asset_name: Stirling-PDF.exe
|
asset_name: Stirling-PDF${{ matrix.file_suffix }}.exe
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
@@ -33,13 +45,11 @@ jobs:
|
|||||||
id: versionNumber
|
id: versionNumber
|
||||||
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
|
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
|
||||||
|
|
||||||
- name: Upload binaries to release
|
- name: Upload jar binaries to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar
|
file: ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar
|
||||||
asset_name: Stirling-PDF.jar
|
asset_name: Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -15,6 +15,13 @@ local.properties
|
|||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
version.properties
|
version.properties
|
||||||
|
pipeline/
|
||||||
|
|
||||||
|
#### Stirling-PDF Files ###
|
||||||
|
customFiles/
|
||||||
|
configs/
|
||||||
|
watchedFolders/
|
||||||
|
|
||||||
|
|
||||||
# Gradle
|
# Gradle
|
||||||
.gradle
|
.gradle
|
||||||
@@ -109,7 +116,7 @@ version.properties
|
|||||||
*.zip
|
*.zip
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.rar
|
*.rar
|
||||||
|
*.db
|
||||||
/build
|
/build
|
||||||
|
|
||||||
/.vscode
|
/.vscode
|
||||||
11
Dockerfile
11
Dockerfile
@@ -1,5 +1,10 @@
|
|||||||
# Build jbig2enc in a separate stage
|
# Build jbig2enc in a separate stage
|
||||||
FROM frooodle/stirling-pdf-base:latest
|
FROM frooodle/stirling-pdf-base:beta4
|
||||||
|
|
||||||
|
ARG VERSION_TAG
|
||||||
|
ENV VERSION_TAG=$VERSION_TAG
|
||||||
|
|
||||||
|
ENV DOCKER_ENABLE_SECURITY=false
|
||||||
|
|
||||||
# Create scripts folder and copy local scripts
|
# Create scripts folder and copy local scripts
|
||||||
RUN mkdir /scripts
|
RUN mkdir /scripts
|
||||||
@@ -11,7 +16,7 @@ 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/
|
||||||
RUN fc-cache -f -v
|
RUN fc-cache -f -v
|
||||||
|
|
||||||
# Copy the application JAR file
|
# Always copy the JAR
|
||||||
COPY build/libs/*.jar app.jar
|
COPY build/libs/*.jar app.jar
|
||||||
|
|
||||||
# Expose the application port
|
# Expose the application port
|
||||||
@@ -19,8 +24,6 @@ EXPOSE 8080
|
|||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV APP_HOME_NAME="Stirling PDF"
|
ENV APP_HOME_NAME="Stirling PDF"
|
||||||
#ENV APP_HOME_DESCRIPTION="Personal PDF Website!"
|
|
||||||
#ENV APP_NAVBAR_NAME="Stirling PDF"
|
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
RUN chmod +x /scripts/init.sh
|
RUN chmod +x /scripts/init.sh
|
||||||
|
|||||||
@@ -13,11 +13,14 @@ RUN apt-get update && \
|
|||||||
# Copy the application JAR file
|
# Copy the application JAR file
|
||||||
COPY build/libs/*.jar app.jar
|
COPY build/libs/*.jar app.jar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Expose the application port
|
# Expose the application port
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF
|
ENV GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF
|
||||||
|
ENV DOCKER_ENABLE_SECURITY=false
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
CMD ["java", "-jar", "/app.jar"]
|
CMD ["java", "-jar", "/app.jar"]
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ COPY build/libs/*.jar app.jar
|
|||||||
# Expose the application port
|
# Expose the application port
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV GROUPS_TO_REMOVE=CLI
|
ENV GROUPS_TO_REMOVE=CLI
|
||||||
|
ENV DOCKER_ENABLE_SECURITY=false
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
CMD ["java", "-jar", "/app.jar"]
|
CMD ["java", "-jar", "/app.jar"]
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ RUN apt-get update && \
|
|||||||
libjpeg-dev && \
|
libjpeg-dev && \
|
||||||
pip install --upgrade pip && \
|
pip install --upgrade pip && \
|
||||||
pip install --no-cache-dir \
|
pip install --no-cache-dir \
|
||||||
opencv-python-headless && \
|
opencv-python-headless WeasyPrint && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Final stage: Copy necessary files from the previous stage
|
# Final stage: Copy necessary files from the previous stage
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|
||||||
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------|
|
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------|
|
||||||
|
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ |
|
||||||
|
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | |
|
||||||
|
| crop | ✔️ | | | | | | | | | ✔️ | |
|
||||||
|
| extract-page | ✔️ | | | | | | | | | ✔️ | |
|
||||||
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
|
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
|
||||||
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
|
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
|
||||||
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
|
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
|
||||||
|
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | |
|
||||||
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
|
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||||
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
|
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
|
||||||
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
|
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||||
@@ -12,6 +17,7 @@
|
|||||||
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||||
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
|
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
|
||||||
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
|
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
|
||||||
|
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | |
|
||||||
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||||
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||||
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||||
@@ -22,14 +28,19 @@
|
|||||||
| cert-sign | | | ✔️ | | | | | | | ✔️ | |
|
| cert-sign | | | ✔️ | | | | | | | ✔️ | |
|
||||||
| change-permissions | | | ✔️ | | | | | | | ✔️ | |
|
| change-permissions | | | ✔️ | | | | | | | ✔️ | |
|
||||||
| remove-password | | | ✔️ | | | | | | | ✔️ | |
|
| remove-password | | | ✔️ | | | | | | | ✔️ | |
|
||||||
|
| sanitize-pdf | | | ✔️ | | | | | | | ✔️ | |
|
||||||
| add-image | | | | ✔️ | | | | | | ✔️ | |
|
| add-image | | | | ✔️ | | | | | | ✔️ | |
|
||||||
|
| add-page-numbers | | | | ✔️ | | | | | | ✔️ | |
|
||||||
|
| auto-rename | | | | ✔️ | | | | | | ✔️ | |
|
||||||
| change-metadata | | | | ✔️ | | | | | | ✔️ | |
|
| change-metadata | | | | ✔️ | | | | | | ✔️ | |
|
||||||
| compare | | | | ✔️ | | | | | | | ✔️ |
|
| compare | | | | ✔️ | | | | | | | ✔️ |
|
||||||
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||||
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||||
| extract-images | | | | ✔️ | | | | | | ✔️ | |
|
| extract-images | | | | ✔️ | | | | | | ✔️ | |
|
||||||
| flatten | | | | ✔️ | | | | | | | |
|
| flatten | | | | ✔️ | | | | | | | ✔️ |
|
||||||
|
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | |
|
||||||
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||||
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||||
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
|
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
|
||||||
|
| show-javascript | | | | ✔️ | | | | | | | ✔️ |
|
||||||
| sign | | | | ✔️ | | | | | | | ✔️ |
|
| sign | | | | ✔️ | | | | | | | ✔️ |
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker.
|
This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker.
|
||||||
|
|
||||||
## How does the OCR Work
|
## How does the OCR Work
|
||||||
Stirling-PDF uses OCRmyPDF which in turn uses tesseract for its text recognition.
|
Stirling-PDF uses [OCRmyPDF](https://github.com/ocrmypdf/OCRmyPDF) which in turn uses tesseract for its text recognition.
|
||||||
All credit goes to them for this awesome work!
|
All credit goes to them for this awesome work!
|
||||||
|
|
||||||
## Language Packs
|
## Language Packs
|
||||||
|
|||||||
57
README.md
57
README.md
@@ -8,6 +8,8 @@
|
|||||||
[](https://www.paypal.com/paypalme/froodleplex)
|
[](https://www.paypal.com/paypalme/froodleplex)
|
||||||
[](https://github.com/sponsors/Frooodle)
|
[](https://github.com/sponsors/Frooodle)
|
||||||
|
|
||||||
|
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Frooodle/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
|
||||||
|
|
||||||
This is a powerful locally hosted web based PDF manipulation tool using docker that allows you to perform various operations on PDF files, such as splitting merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application started as a 100% ChatGPT-made application and has evolved to include a wide range of features to handle all your PDF needs.
|
This is a powerful locally hosted web based PDF manipulation tool using docker that allows you to perform various operations on PDF files, such as splitting merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application started as a 100% ChatGPT-made application and has evolved to include a wide range of features to handle all your PDF needs.
|
||||||
|
|
||||||
Stirling PDF makes no outbound calls for any record keeping or tracking.
|
Stirling PDF makes no outbound calls for any record keeping or tracking.
|
||||||
@@ -27,6 +29,11 @@ Feel free to request any features or bug fixes either in github issues or our [D
|
|||||||
- Convert PDFs to and from images
|
- Convert PDFs to and from images
|
||||||
- Reorganize PDF pages into different orders.
|
- Reorganize PDF pages into different orders.
|
||||||
- Add/Generate signatures
|
- Add/Generate signatures
|
||||||
|
- Format PDFs into a multi-paged page
|
||||||
|
- Scale page contents size by set %
|
||||||
|
- Adjust Contrast
|
||||||
|
- Crop PDF
|
||||||
|
- Auto Split PDF (With physically scanned page dividers)
|
||||||
- Flatten PDFs
|
- Flatten PDFs
|
||||||
- Repair PDFs
|
- Repair PDFs
|
||||||
- Detect and remove blank pages
|
- Detect and remove blank pages
|
||||||
@@ -39,8 +46,14 @@ Feel free to request any features or bug fixes either in github issues or our [D
|
|||||||
- Add watermark(s)
|
- Add watermark(s)
|
||||||
- Convert Any common file to PDF (using LibreOffice)
|
- Convert Any common file to PDF (using LibreOffice)
|
||||||
- Convert PDF to Word/Powerpoint/Others (using LibreOffice)
|
- Convert PDF to Word/Powerpoint/Others (using LibreOffice)
|
||||||
|
- Convert HTML to PDF
|
||||||
|
- URL to PDF
|
||||||
- Extract images from PDF
|
- Extract images from PDF
|
||||||
|
- Extract images from Scans
|
||||||
|
- Add page numbers
|
||||||
|
- Auto rename file by detecting PDF header text
|
||||||
- OCR on PDF (Using OCRMyPDF)
|
- OCR on PDF (Using OCRMyPDF)
|
||||||
|
- PDF/A conversion (Using OCRMyPDF)
|
||||||
- Edit metadata
|
- Edit metadata
|
||||||
- Dark mode support.
|
- Dark mode support.
|
||||||
- Custom download options (see [here](https://github.com/Frooodle/Stirling-PDF/blob/main/images/settings.png) for example)
|
- Custom download options (see [here](https://github.com/Frooodle/Stirling-PDF/blob/main/images/settings.png) for example)
|
||||||
@@ -86,6 +99,8 @@ docker run -d \
|
|||||||
|
|
||||||
|
|
||||||
Can also add these for customisation but are not required
|
Can also add these for customisation but are not required
|
||||||
|
-v /location/of/extraConfigs:/configs \
|
||||||
|
-v /location/of/customFiles:/customFiles \
|
||||||
-e APP_HOME_NAME="Stirling PDF" \
|
-e APP_HOME_NAME="Stirling PDF" \
|
||||||
-e APP_HOME_DESCRIPTION="Your locally hosted one-stop-shop for all your PDF needs." \
|
-e APP_HOME_DESCRIPTION="Your locally hosted one-stop-shop for all your PDF needs." \
|
||||||
-e APP_NAVBAR_NAME="Stirling PDF" \
|
-e APP_NAVBAR_NAME="Stirling PDF" \
|
||||||
@@ -104,6 +119,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /location/of/trainingData:/usr/share/tesseract-ocr/4.00/tessdata #Required for extra OCR languages
|
- /location/of/trainingData:/usr/share/tesseract-ocr/4.00/tessdata #Required for extra OCR languages
|
||||||
# - /location/of/extraConfigs:/configs
|
# - /location/of/extraConfigs:/configs
|
||||||
|
# - /location/of/customFiles:/customFiles/
|
||||||
# environment:
|
# environment:
|
||||||
# APP_LOCALE: en_GB
|
# APP_LOCALE: en_GB
|
||||||
# APP_HOME_NAME: Stirling PDF
|
# APP_HOME_NAME: Stirling PDF
|
||||||
@@ -160,28 +176,43 @@ Using the same method you can also change
|
|||||||
- Enable/Disable search engine visiblility with ALLOW_GOOGLE_VISIBILITY with true / false values. Default disable visiblility.
|
- Enable/Disable search engine visiblility with ALLOW_GOOGLE_VISIBILITY with true / false values. Default disable visiblility.
|
||||||
- Change root URI for Stirling-PDF ie change server.com/ to server.com/pdf-app by running APP_ROOT_PATH as pdf-app
|
- Change root URI for Stirling-PDF ie change server.com/ to server.com/pdf-app by running APP_ROOT_PATH as pdf-app
|
||||||
- Disable and remove endpoints and functionality from Stirling-PDF. Currently the endpoints ENDPOINTS_TO_REMOVE and GROUPS_TO_REMOVE can include comma seperated lists of endpoints and groups to disable as example ENDPOINTS_TO_REMOVE=img-to-pdf,remove-pages would disable both image to pdf and remove pages, GROUPS_TO_REMOVE=LibreOffice Would disable all things that use LibreOffice. You can see a list of all endpoints and groups [here](https://github.com/Frooodle/Stirling-PDF/blob/main/groups.md)
|
- Disable and remove endpoints and functionality from Stirling-PDF. Currently the endpoints ENDPOINTS_TO_REMOVE and GROUPS_TO_REMOVE can include comma seperated lists of endpoints and groups to disable as example ENDPOINTS_TO_REMOVE=img-to-pdf,remove-pages would disable both image to pdf and remove pages, GROUPS_TO_REMOVE=LibreOffice Would disable all things that use LibreOffice. You can see a list of all endpoints and groups [here](https://github.com/Frooodle/Stirling-PDF/blob/main/groups.md)
|
||||||
|
- Change the max file size allowed through the server with the environment variable MAX_FILE_SIZE. default 2000MB
|
||||||
|
- Customise static files such as app logo by placing files in the /customFiles/static/ directory. Example to customise app logo is placing a /customFiles/static/favicon.svg to override current SVG. This can be used to change any images/icons/css/fonts/js etc in Stirling-PDF
|
||||||
|
- Enable/Disable metric api endpoints with ENABLE_API_METRICS. Default enabled
|
||||||
|
|
||||||
## API
|
## API
|
||||||
For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation
|
For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation
|
||||||
[here](https://app.swaggerhub.com/apis-docs/Frooodle/Stirling-PDF/) or navigate to /swagger-ui/index.html of your stirling-pdf instance for your versions documentation
|
[here](https://app.swaggerhub.com/apis-docs/Frooodle/Stirling-PDF/) or navigate to /swagger-ui/index.html of your stirling-pdf instance for your versions documentation (Or by following the API button in your settings of Stirling-PDF)
|
||||||
|
|
||||||
|
|
||||||
|
## Login authentication (CURRENTLY ALPHA TAG ONLY)
|
||||||
|
### Prerequisites:
|
||||||
|
- User must have the folder ./configs volumed within docker so that it is retained during updates.
|
||||||
|
- The environment variable 'login.enabled' must be set to true
|
||||||
|
- The environment variables "INITIAL_USERNAME" and "INITIAL_PASSWORD" must also be populated (only required on first boot to create initial user, ignored after.)
|
||||||
|
|
||||||
|
Once the above has been done, on restart a new stirling-pdf-DB.mv.db will show if everything worked.
|
||||||
|
|
||||||
|
When you login to Stirling PDF you will be redirected to /login page to login with those credentials. After login everything should function as normal
|
||||||
|
|
||||||
|
To access your account settings go to Account settings in the settings cog menu (top right in navbar) this Account settings menu is also where you find your API key.
|
||||||
|
|
||||||
|
To add new users go to bottom of Account settings and hit 'Admin Settings', here you can add new users. The different roles mentioned within this are for rate limiting. This is a Work in progress which will be expanding on more in future
|
||||||
|
|
||||||
|
For API usage you must provide a header with 'X-API-Key' and the associated API key for that user.
|
||||||
|
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### Q1: Can you add authentication in Stirling PDF?
|
### Q1: What are your planned features?
|
||||||
There is no Auth within Stirling PDF and there is none planned. This feature will not be added. Instead we recommended you use trusted and secure authentication software like Authentik or Authelia.
|
|
||||||
|
|
||||||
### Q2: What are your planned features?
|
|
||||||
- Crop
|
|
||||||
- Progress bar/Tracking
|
- Progress bar/Tracking
|
||||||
- Full custom logic pipelines to combine multiple operations together.
|
- Full custom logic pipelines to combine multiple operations together.
|
||||||
- Folder support with auto scanning to perform operations on
|
- Folder support with auto scanning to perform operations on
|
||||||
- Redact sections of pages
|
- Redact text (Via UI)
|
||||||
- Add page numbers
|
- Add Forms
|
||||||
- Auto rename (Renames file based on file title text)
|
- Annotations
|
||||||
- URL to PDF
|
- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
|
||||||
- Change contrast
|
- Fill forms mannual and automatic
|
||||||
|
|
||||||
### Q3: Why is my application downloading .htm files?
|
### Q2: Why is my application downloading .htm files?
|
||||||
This is a issue caused commonly by your NGINX congifuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. client_max_body_size SIZE; Where "SIZE" is 50M for example for 50MB files.
|
This is a issue caused commonly by your NGINX congifuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. client_max_body_size SIZE; Where "SIZE" is 50M for example for 50MB files.
|
||||||
|
|||||||
@@ -13,26 +13,37 @@
|
|||||||
|
|
||||||
Operation | Ultra-Lite | Lite | Full
|
Operation | Ultra-Lite | Lite | Full
|
||||||
--------------------|------------|------|-----
|
--------------------|------------|------|-----
|
||||||
|
add-page-numbers | ✔️ | ✔️ | ✔️
|
||||||
add-password | ✔️ | ✔️ | ✔️
|
add-password | ✔️ | ✔️ | ✔️
|
||||||
|
add-image | ✔️ | ✔️ | ✔️
|
||||||
add-watermark | ✔️ | ✔️ | ✔️
|
add-watermark | ✔️ | ✔️ | ✔️
|
||||||
|
adjust-contrast | ✔️ | ✔️ | ✔️
|
||||||
|
auto-split-pdf | ✔️ | ✔️ | ✔️
|
||||||
|
auto-rename | ✔️ | ✔️ | ✔️
|
||||||
cert-sign | ✔️ | ✔️ | ✔️
|
cert-sign | ✔️ | ✔️ | ✔️
|
||||||
|
crop | ✔️ | ✔️ | ✔️
|
||||||
change-metadata | ✔️ | ✔️ | ✔️
|
change-metadata | ✔️ | ✔️ | ✔️
|
||||||
change-permissions | ✔️ | ✔️ | ✔️
|
change-permissions | ✔️ | ✔️ | ✔️
|
||||||
compare | ✔️ | ✔️ | ✔️
|
compare | ✔️ | ✔️ | ✔️
|
||||||
|
extract-page | ✔️ | ✔️ | ✔️
|
||||||
extract-images | ✔️ | ✔️ | ✔️
|
extract-images | ✔️ | ✔️ | ✔️
|
||||||
flatten | ✔️ | ✔️ | ✔️
|
flatten | ✔️ | ✔️ | ✔️
|
||||||
|
get-info-on-pdf | ✔️ | ✔️ | ✔️
|
||||||
img-to-pdf | ✔️ | ✔️ | ✔️
|
img-to-pdf | ✔️ | ✔️ | ✔️
|
||||||
|
markdown-to-pdf | ✔️ | ✔️ | ✔️
|
||||||
merge-pdfs | ✔️ | ✔️ | ✔️
|
merge-pdfs | ✔️ | ✔️ | ✔️
|
||||||
multi-page-layout | ✔️ | ✔️ | ✔️
|
multi-page-layout | ✔️ | ✔️ | ✔️
|
||||||
pdf-organizer | ✔️ | ✔️ | ✔️
|
pdf-organizer | ✔️ | ✔️ | ✔️
|
||||||
pdf-to-img | ✔️ | ✔️ | ✔️
|
pdf-to-img | ✔️ | ✔️ | ✔️
|
||||||
|
pdf-to-single-page | ✔️ | ✔️ | ✔️
|
||||||
remove-pages | ✔️ | ✔️ | ✔️
|
remove-pages | ✔️ | ✔️ | ✔️
|
||||||
remove-password | ✔️ | ✔️ | ✔️
|
remove-password | ✔️ | ✔️ | ✔️
|
||||||
rotate-pdf | ✔️ | ✔️ | ✔️
|
rotate-pdf | ✔️ | ✔️ | ✔️
|
||||||
|
sanitize-pdf | ✔️ | ✔️ | ✔️
|
||||||
scale-pages | ✔️ | ✔️ | ✔️
|
scale-pages | ✔️ | ✔️ | ✔️
|
||||||
sign | ✔️ | ✔️ | ✔️
|
sign | ✔️ | ✔️ | ✔️
|
||||||
|
show-javascript | ✔️ | ✔️ | ✔️
|
||||||
split-pdfs | ✔️ | ✔️ | ✔️
|
split-pdfs | ✔️ | ✔️ | ✔️
|
||||||
add-image | ✔️ | ✔️ | ✔️
|
|
||||||
file-to-pdf | | ✔️ | ✔️
|
file-to-pdf | | ✔️ | ✔️
|
||||||
pdf-to-html | | ✔️ | ✔️
|
pdf-to-html | | ✔️ | ✔️
|
||||||
pdf-to-presentation | | ✔️ | ✔️
|
pdf-to-presentation | | ✔️ | ✔️
|
||||||
|
|||||||
49
build.gradle
49
build.gradle
@@ -1,20 +1,38 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.1.1'
|
id 'org.springframework.boot' version '3.1.2'
|
||||||
id 'io.spring.dependency-management' version '1.1.0'
|
id 'io.spring.dependency-management' version '1.1.2'
|
||||||
id 'org.springdoc.openapi-gradle-plugin' version '1.6.0'
|
id 'org.springdoc.openapi-gradle-plugin' version '1.6.0'
|
||||||
id "io.swagger.swaggerhub" version "1.2.0"
|
id "io.swagger.swaggerhub" version "1.2.0"
|
||||||
id 'edu.sc.seis.launch4j' version '3.0.3'
|
id 'edu.sc.seis.launch4j' version '3.0.3'
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'stirling.software'
|
group = 'stirling.software'
|
||||||
version = '0.10.3'
|
version = '0.13.0'
|
||||||
sourceCompatibility = '17'
|
sourceCompatibility = '17'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
if (System.getenv('DOCKER_ENABLE_SECURITY') == 'false') {
|
||||||
|
exclude 'stirling/software/SPDF/config/security/**'
|
||||||
|
exclude 'stirling/software/SPDF/controller/api/UserController.java'
|
||||||
|
exclude 'stirling/software/SPDF/controller/web/AccountWebController.java'
|
||||||
|
exclude 'stirling/software/SPDF/model/ApiKeyAuthenticationToken.java'
|
||||||
|
exclude 'stirling/software/SPDF/model/Authority.java'
|
||||||
|
exclude 'stirling/software/SPDF/model/PersistentLogin.java'
|
||||||
|
exclude 'stirling/software/SPDF/model/User.java'
|
||||||
|
exclude 'stirling/software/SPDF/repository/**'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
openApi {
|
openApi {
|
||||||
apiDocsUrl = "http://localhost:8080/v3/api-docs"
|
apiDocsUrl = "http://localhost:8080/v3/api-docs"
|
||||||
outputDir = file("$projectDir")
|
outputDir = file("$projectDir")
|
||||||
@@ -45,9 +63,21 @@ launch4j {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web:3.1.0'
|
implementation 'org.yaml:snakeyaml:2.1'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.1'
|
implementation 'org.springframework.boot:spring-boot-starter-web:3.1.2'
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.0'
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.2'
|
||||||
|
|
||||||
|
if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-security:3.1.2'
|
||||||
|
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
|
||||||
|
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
|
||||||
|
implementation "com.h2database:h2"
|
||||||
|
}
|
||||||
|
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.2'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio
|
// https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio
|
||||||
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
|
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
|
||||||
implementation 'commons-io:commons-io:2.13.0'
|
implementation 'commons-io:commons-io:2.13.0'
|
||||||
@@ -55,12 +85,17 @@ dependencies {
|
|||||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
|
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
|
||||||
|
|
||||||
//general PDF
|
//general PDF
|
||||||
implementation 'org.apache.pdfbox:pdfbox:2.0.28'
|
implementation 'org.apache.pdfbox:pdfbox:2.0.29'
|
||||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
|
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
|
||||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
|
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
|
||||||
implementation 'com.itextpdf:itext7-core:7.2.5'
|
implementation 'com.itextpdf:itext7-core:7.2.5'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
implementation 'io.micrometer:micrometer-core'
|
implementation 'io.micrometer:micrometer-core'
|
||||||
|
implementation group: 'com.google.zxing', name: 'core', version: '3.5.1'
|
||||||
|
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
||||||
|
implementation 'org.commonmark:commonmark:0.21.0'
|
||||||
|
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
|
||||||
|
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'
|
||||||
|
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 118 KiB |
80
scripts/PropSync.java
Normal file
80
scripts/PropSync.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package stirling.software.Stirling.Stats;
|
||||||
|
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.nio.charset.MalformedInputException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class PropSync {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
File folder = new File("C:\\Users\\systo\\git\\Stirling-PDF\\src\\main\\resources");
|
||||||
|
File[] files = folder.listFiles((dir, name) -> name.matches("messages_.*\\.properties"));
|
||||||
|
|
||||||
|
List<String> enLines = Files.readAllLines(Paths.get(folder + "\\messages_en_GB.properties"), StandardCharsets.UTF_8);
|
||||||
|
Map<String, String> enProps = linesToProps(enLines);
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
if (!file.getName().equals("messages_en_GB.properties")) {
|
||||||
|
System.out.println("Processing file: " + file.getName());
|
||||||
|
List<String> lines;
|
||||||
|
try {
|
||||||
|
lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
|
||||||
|
} catch (MalformedInputException e) {
|
||||||
|
System.out.println("Skipping due to not UTF8 format for file: " + file.getName());
|
||||||
|
continue;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> currentProps = linesToProps(lines);
|
||||||
|
List<String> newLines = syncPropsWithLines(enProps, currentProps, enLines);
|
||||||
|
|
||||||
|
Files.write(file.toPath(), newLines, StandardCharsets.UTF_8);
|
||||||
|
System.out.println("Finished processing file: " + file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> linesToProps(List<String> lines) {
|
||||||
|
Map<String, String> props = new LinkedHashMap<>();
|
||||||
|
for (String line : lines) {
|
||||||
|
if (!line.trim().isEmpty() && line.contains("=")) {
|
||||||
|
String[] parts = line.split("=", 2);
|
||||||
|
props.put(parts[0].trim(), parts[1].trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> syncPropsWithLines(Map<String, String> enProps, Map<String, String> currentProps, List<String> enLines) {
|
||||||
|
List<String> newLines = new ArrayList<>();
|
||||||
|
boolean needsTranslateComment = false; // flag to check if we need to add "TODO: Translate"
|
||||||
|
|
||||||
|
for (String line : enLines) {
|
||||||
|
if (line.contains("=")) {
|
||||||
|
String key = line.split("=", 2)[0].trim();
|
||||||
|
|
||||||
|
if (currentProps.containsKey(key)) {
|
||||||
|
newLines.add(key + "=" + currentProps.get(key));
|
||||||
|
needsTranslateComment = false;
|
||||||
|
} else {
|
||||||
|
if (!needsTranslateComment) {
|
||||||
|
newLines.add("##########################");
|
||||||
|
newLines.add("### TODO: Translate ###");
|
||||||
|
newLines.add("##########################");
|
||||||
|
needsTranslateComment = true;
|
||||||
|
}
|
||||||
|
newLines.add(line);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// handle comments and other non-property lines
|
||||||
|
newLines.add(line);
|
||||||
|
needsTranslateComment = false; // reset the flag when we encounter comments or empty lines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newLines;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,5 +5,27 @@ echo "Copying original files without overwriting existing files"
|
|||||||
mkdir -p /usr/share/tesseract-ocr
|
mkdir -p /usr/share/tesseract-ocr
|
||||||
cp -rn /usr/share/tesseract-ocr-original/* /usr/share/tesseract-ocr
|
cp -rn /usr/share/tesseract-ocr-original/* /usr/share/tesseract-ocr
|
||||||
|
|
||||||
|
# Check if TESSERACT_LANGS environment variable is set and is not empty
|
||||||
|
if [[ -n "$TESSERACT_LANGS" ]]; then
|
||||||
|
# Convert comma-separated values to a space-separated list
|
||||||
|
LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ')
|
||||||
|
|
||||||
|
# Install each language pack
|
||||||
|
for LANG in $LANGS; do
|
||||||
|
apt-get install -y "tesseract-ocr-$LANG"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for DOCKER_ENABLE_SECURITY and download the appropriate JAR if required
|
||||||
|
if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
|
||||||
|
echo "Downloading from: https://github.com/Frooodle/Stirling-PDF/releases/download/$VERSION_TAG/Stirling-PDF-with-login.jar"
|
||||||
|
curl -L -o new-app.jar https://github.com/Frooodle/Stirling-PDF/releases/download/$VERSION_TAG/Stirling-PDF-with-login.jar
|
||||||
|
if [ $? -eq 0 ]; then # checks if curl was successful
|
||||||
|
rm -f app.jar
|
||||||
|
mv new-app.jar app.jar
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Run the main command
|
# Run the main command
|
||||||
exec "$@"
|
exec "$@"
|
||||||
@@ -1,14 +1,20 @@
|
|||||||
package stirling.software.SPDF;
|
package stirling.software.SPDF;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import stirling.software.SPDF.config.ConfigInitializer;
|
||||||
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
|
||||||
//@EnableScheduling
|
//@EnableScheduling
|
||||||
public class SPdfApplication {
|
public class SPdfApplication {
|
||||||
|
|
||||||
@@ -42,13 +48,28 @@ public class SPdfApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(SPdfApplication.class, args);
|
SpringApplication app = new SpringApplication(SPdfApplication.class);
|
||||||
|
app.addInitializers(new ConfigInitializer());
|
||||||
|
if (Files.exists(Paths.get("configs/settings.yml"))) {
|
||||||
|
app.setDefaultProperties(Collections.singletonMap("spring.config.location", "file:configs/settings.yml"));
|
||||||
|
} else {
|
||||||
|
System.out.println("External configuration file 'configs/settings.yml' does not exist. Using default configuration and environment configuration instead.");
|
||||||
|
}
|
||||||
|
app.run(args);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GeneralUtils.createDir("customFiles/static/");
|
||||||
|
GeneralUtils.createDir("customFiles/templates/");
|
||||||
|
GeneralUtils.createDir("config");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println("Stirling-PDF Started.");
|
System.out.println("Stirling-PDF Started.");
|
||||||
|
|
||||||
String port = System.getProperty("local.server.port");
|
String port = System.getProperty("local.server.port");
|
||||||
|
|||||||
@@ -1,16 +1,26 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
@Bean(name = "loginEnabled")
|
||||||
|
public boolean loginEnabled() {
|
||||||
|
System.out.println(applicationProperties.toString());
|
||||||
|
return applicationProperties.getSecurity().getEnableLogin();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean(name = "appName")
|
@Bean(name = "appName")
|
||||||
public String appName() {
|
public String appName() {
|
||||||
String appName = System.getProperty("APP_HOME_NAME");
|
String homeTitle = applicationProperties.getUi().getAppName();
|
||||||
if (appName == null)
|
return (homeTitle != null) ? homeTitle : "Stirling PDF";
|
||||||
appName = System.getenv("APP_HOME_NAME");
|
|
||||||
return (appName != null) ? appName : "Stirling PDF";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "appVersion")
|
@Bean(name = "appVersion")
|
||||||
@@ -21,22 +31,24 @@ public class AppConfig {
|
|||||||
|
|
||||||
@Bean(name = "homeText")
|
@Bean(name = "homeText")
|
||||||
public String homeText() {
|
public String homeText() {
|
||||||
String homeText = System.getProperty("APP_HOME_DESCRIPTION");
|
return (applicationProperties.getUi().getHomeDescription() != null) ? applicationProperties.getUi().getHomeDescription() : "null";
|
||||||
if (homeText == null)
|
|
||||||
homeText = System.getenv("APP_HOME_DESCRIPTION");
|
|
||||||
return (homeText != null) ? homeText : "null";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean(name = "navBarText")
|
@Bean(name = "navBarText")
|
||||||
public String navBarText() {
|
public String navBarText() {
|
||||||
String navBarText = System.getProperty("APP_NAVBAR_NAME");
|
String defaultNavBar = applicationProperties.getUi().getAppNameNavbar() != null ? applicationProperties.getUi().getAppNameNavbar() : applicationProperties.getUi().getAppName();
|
||||||
if (navBarText == null)
|
return (defaultNavBar != null) ? defaultNavBar : "Stirling PDF";
|
||||||
navBarText = System.getenv("APP_NAVBAR_NAME");
|
|
||||||
if (navBarText == null)
|
|
||||||
navBarText = System.getProperty("APP_HOME_NAME");
|
|
||||||
if (navBarText == null)
|
|
||||||
navBarText = System.getenv("APP_HOME_NAME");
|
|
||||||
|
|
||||||
return (navBarText != null) ? navBarText : "Stirling PDF";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean(name = "rateLimit")
|
||||||
|
public boolean rateLimit() {
|
||||||
|
String appName = System.getProperty("rateLimit");
|
||||||
|
if (appName == null)
|
||||||
|
appName = System.getenv("rateLimit");
|
||||||
|
System.out.println("rateLimit=" + appName);
|
||||||
|
return (appName != null) ? Boolean.valueOf(appName) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package stirling.software.SPDF.config;
|
|||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.LocaleResolver;
|
import org.springframework.web.servlet.LocaleResolver;
|
||||||
@@ -10,9 +11,14 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|||||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||||
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class Beans implements WebMvcConfigurer {
|
public class Beans implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(localeChangeInterceptor());
|
registry.addInterceptor(localeChangeInterceptor());
|
||||||
@@ -30,9 +36,8 @@ public class Beans implements WebMvcConfigurer {
|
|||||||
public LocaleResolver localeResolver() {
|
public LocaleResolver localeResolver() {
|
||||||
SessionLocaleResolver slr = new SessionLocaleResolver();
|
SessionLocaleResolver slr = new SessionLocaleResolver();
|
||||||
|
|
||||||
String appLocaleEnv = System.getProperty("APP_LOCALE");
|
|
||||||
if (appLocaleEnv == null)
|
String appLocaleEnv = applicationProperties.getSystem().getDefaultLocale();
|
||||||
appLocaleEnv = System.getenv("APP_LOCALE");
|
|
||||||
Locale defaultLocale = Locale.UK; // Fallback to UK locale if environment variable is not set
|
Locale defaultLocale = Locale.UK; // Fallback to UK locale if environment variable is not set
|
||||||
|
|
||||||
if (appLocaleEnv != null && !appLocaleEnv.isEmpty()) {
|
if (appLocaleEnv != null && !appLocaleEnv.isEmpty()) {
|
||||||
|
|||||||
@@ -1,30 +1,20 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public class CleanUrlInterceptor implements HandlerInterceptor {
|
public class CleanUrlInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints");
|
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints", "logout", "error", "file");
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||||
@@ -42,6 +32,7 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
|
|||||||
if (keyValue.length != 2) {
|
if (keyValue.length != 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ALLOWED_PARAMS.contains(keyValue[0])) {
|
if (ALLOWED_PARAMS.contains(keyValue[0])) {
|
||||||
parameters.put(keyValue[0], keyValue[1]);
|
parameters.put(keyValue[0], keyValue[1]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package stirling.software.SPDF.config;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
|
public class ConfigInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||||
|
try {
|
||||||
|
ensureConfigExists();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to initialize application configuration", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ensureConfigExists() throws IOException {
|
||||||
|
// Define the path to the external config directory
|
||||||
|
Path destPath = Paths.get("configs", "settings.yml");
|
||||||
|
|
||||||
|
// Check if the file already exists
|
||||||
|
if (Files.notExists(destPath)) {
|
||||||
|
// Ensure the destination directory exists
|
||||||
|
Files.createDirectories(destPath.getParent());
|
||||||
|
|
||||||
|
// Copy the resource from classpath to the external directory
|
||||||
|
try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
|
||||||
|
if (in != null) {
|
||||||
|
Files.copy(in, destPath);
|
||||||
|
} else {
|
||||||
|
throw new FileNotFoundException("Resource file not found: settings.yml.template");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,20 +1,28 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
@Service
|
@Service
|
||||||
public class EndpointConfiguration {
|
public class EndpointConfiguration {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
|
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
|
||||||
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
||||||
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
|
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public EndpointConfiguration() {
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public EndpointConfiguration(ApplicationProperties applicationProperties) {
|
||||||
|
this.applicationProperties = applicationProperties;
|
||||||
init();
|
init();
|
||||||
processEnvironmentConfigs();
|
processEnvironmentConfigs();
|
||||||
}
|
}
|
||||||
@@ -68,6 +76,11 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("PageOps", "rotate-pdf");
|
addEndpointToGroup("PageOps", "rotate-pdf");
|
||||||
addEndpointToGroup("PageOps", "multi-page-layout");
|
addEndpointToGroup("PageOps", "multi-page-layout");
|
||||||
addEndpointToGroup("PageOps", "scale-pages");
|
addEndpointToGroup("PageOps", "scale-pages");
|
||||||
|
addEndpointToGroup("PageOps", "adjust-contrast");
|
||||||
|
addEndpointToGroup("PageOps", "crop");
|
||||||
|
addEndpointToGroup("PageOps", "auto-split-pdf");
|
||||||
|
addEndpointToGroup("PageOps", "extract-page");
|
||||||
|
addEndpointToGroup("PageOps", "pdf-to-single-page");
|
||||||
|
|
||||||
// Adding endpoints to "Convert" group
|
// Adding endpoints to "Convert" group
|
||||||
addEndpointToGroup("Convert", "pdf-to-img");
|
addEndpointToGroup("Convert", "pdf-to-img");
|
||||||
@@ -80,6 +93,9 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Convert", "pdf-to-text");
|
addEndpointToGroup("Convert", "pdf-to-text");
|
||||||
addEndpointToGroup("Convert", "pdf-to-html");
|
addEndpointToGroup("Convert", "pdf-to-html");
|
||||||
addEndpointToGroup("Convert", "pdf-to-xml");
|
addEndpointToGroup("Convert", "pdf-to-xml");
|
||||||
|
addEndpointToGroup("Convert", "html-to-pdf");
|
||||||
|
addEndpointToGroup("Convert", "url-to-pdf");
|
||||||
|
addEndpointToGroup("Convert", "markdown-to-pdf");
|
||||||
|
|
||||||
// Adding endpoints to "Security" group
|
// Adding endpoints to "Security" group
|
||||||
addEndpointToGroup("Security", "add-password");
|
addEndpointToGroup("Security", "add-password");
|
||||||
@@ -87,7 +103,7 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Security", "change-permissions");
|
addEndpointToGroup("Security", "change-permissions");
|
||||||
addEndpointToGroup("Security", "add-watermark");
|
addEndpointToGroup("Security", "add-watermark");
|
||||||
addEndpointToGroup("Security", "cert-sign");
|
addEndpointToGroup("Security", "cert-sign");
|
||||||
|
addEndpointToGroup("Security", "sanitize-pdf");
|
||||||
|
|
||||||
|
|
||||||
// Adding endpoints to "Other" group
|
// Adding endpoints to "Other" group
|
||||||
@@ -102,10 +118,10 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Other", "repair");
|
addEndpointToGroup("Other", "repair");
|
||||||
addEndpointToGroup("Other", "remove-blanks");
|
addEndpointToGroup("Other", "remove-blanks");
|
||||||
addEndpointToGroup("Other", "compare");
|
addEndpointToGroup("Other", "compare");
|
||||||
|
addEndpointToGroup("Other", "add-page-numbers");
|
||||||
|
addEndpointToGroup("Other", "auto-rename");
|
||||||
|
addEndpointToGroup("Other", "get-info-on-pdf");
|
||||||
|
addEndpointToGroup("Other", "show-javascript");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -123,12 +139,15 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("CLI", "pdf-to-html");
|
addEndpointToGroup("CLI", "pdf-to-html");
|
||||||
addEndpointToGroup("CLI", "pdf-to-xml");
|
addEndpointToGroup("CLI", "pdf-to-xml");
|
||||||
addEndpointToGroup("CLI", "ocr-pdf");
|
addEndpointToGroup("CLI", "ocr-pdf");
|
||||||
|
addEndpointToGroup("CLI", "html-to-pdf");
|
||||||
|
addEndpointToGroup("CLI", "url-to-pdf");
|
||||||
|
|
||||||
|
|
||||||
//python
|
//python
|
||||||
addEndpointToGroup("Python", "extract-image-scans");
|
addEndpointToGroup("Python", "extract-image-scans");
|
||||||
addEndpointToGroup("Python", "remove-blanks");
|
addEndpointToGroup("Python", "remove-blanks");
|
||||||
|
addEndpointToGroup("Python", "html-to-pdf");
|
||||||
|
addEndpointToGroup("Python", "url-to-pdf");
|
||||||
|
|
||||||
//openCV
|
//openCV
|
||||||
addEndpointToGroup("OpenCV", "extract-image-scans");
|
addEndpointToGroup("OpenCV", "extract-image-scans");
|
||||||
@@ -168,29 +187,38 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Java", "cert-sign");
|
addEndpointToGroup("Java", "cert-sign");
|
||||||
addEndpointToGroup("Java", "multi-page-layout");
|
addEndpointToGroup("Java", "multi-page-layout");
|
||||||
addEndpointToGroup("Java", "scale-pages");
|
addEndpointToGroup("Java", "scale-pages");
|
||||||
|
addEndpointToGroup("Java", "add-page-numbers");
|
||||||
|
addEndpointToGroup("Java", "auto-rename");
|
||||||
|
addEndpointToGroup("Java", "auto-split-pdf");
|
||||||
|
addEndpointToGroup("Java", "sanitize-pdf");
|
||||||
|
addEndpointToGroup("Java", "crop");
|
||||||
|
addEndpointToGroup("Java", "get-info-on-pdf");
|
||||||
|
addEndpointToGroup("Java", "extract-page");
|
||||||
|
addEndpointToGroup("Java", "pdf-to-single-page");
|
||||||
|
addEndpointToGroup("Java", "markdown-to-pdf");
|
||||||
|
addEndpointToGroup("Java", "show-javascript");
|
||||||
|
|
||||||
//Javascript
|
//Javascript
|
||||||
addEndpointToGroup("Javascript", "pdf-organizer");
|
addEndpointToGroup("Javascript", "pdf-organizer");
|
||||||
addEndpointToGroup("Javascript", "sign");
|
addEndpointToGroup("Javascript", "sign");
|
||||||
addEndpointToGroup("Javascript", "compare");
|
addEndpointToGroup("Javascript", "compare");
|
||||||
|
addEndpointToGroup("Javascript", "adjust-contrast");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processEnvironmentConfigs() {
|
private void processEnvironmentConfigs() {
|
||||||
String endpointsToRemove = System.getenv("ENDPOINTS_TO_REMOVE");
|
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
||||||
String groupsToRemove = System.getenv("GROUPS_TO_REMOVE");
|
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
||||||
|
|
||||||
if (endpointsToRemove != null) {
|
if (endpointsToRemove != null) {
|
||||||
String[] endpoints = endpointsToRemove.split(",");
|
for (String endpoint : endpointsToRemove) {
|
||||||
for (String endpoint : endpoints) {
|
|
||||||
disableEndpoint(endpoint.trim());
|
disableEndpoint(endpoint.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupsToRemove != null) {
|
if (groupsToRemove != null) {
|
||||||
String[] groups = groupsToRemove.split(",");
|
for (String group : groupsToRemove) {
|
||||||
for (String group : groups) {
|
|
||||||
disableGroup(group.trim());
|
disableGroup(group.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class MetricsFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
//System.out.println("uri="+uri + ", method=" + request.getMethod() );
|
//System.out.println("uri="+uri + ", method=" + request.getMethod() );
|
||||||
// Ignore static resources
|
// Ignore static resources
|
||||||
if (!(uri.startsWith("/js") || uri.startsWith("/images") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) {
|
if (!(uri.startsWith("/js") || uri.startsWith("api-docs") || uri.endsWith("robots.txt") || uri.startsWith("/images") || uri.endsWith(".png") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) {
|
||||||
Counter counter = Counter.builder("http.requests")
|
Counter counter = Counter.builder("http.requests")
|
||||||
.tag("uri", uri)
|
.tag("uri", uri)
|
||||||
.tag("method", request.getMethod())
|
.tag("method", request.getMethod())
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.context.event.ContextRefreshedEvent;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class StartupApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
|
||||||
|
|
||||||
|
public static LocalDateTime startTime;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||||
|
startTime = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ package stirling.software.SPDF.config;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@@ -15,4 +16,12 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
|||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(endpointInterceptor);
|
registry.addInterceptor(endpointInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
// Handler for external static resources
|
||||||
|
registry.addResourceHandler("/**")
|
||||||
|
.addResourceLocations("file:customFiles/static/", "classpath:/static/");
|
||||||
|
//.setCachePeriod(0); // Optional: disable caching
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||||
|
import org.springframework.core.env.PropertiesPropertySource;
|
||||||
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.core.io.support.EncodedResource;
|
||||||
|
import org.springframework.core.io.support.PropertySourceFactory;
|
||||||
|
public class YamlPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
|
||||||
|
throws IOException {
|
||||||
|
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||||
|
factory.setResources(encodedResource.getResource());
|
||||||
|
|
||||||
|
Properties properties = factory.getObject();
|
||||||
|
|
||||||
|
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.LockedException;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
|
||||||
|
setDefaultFailureUrl("/login?error=badcredentials");
|
||||||
|
} else if (exception.getClass().isAssignableFrom(LockedException.class)) {
|
||||||
|
setDefaultFailureUrl("/login?error=locked");
|
||||||
|
}
|
||||||
|
super.onAuthenticationFailure(request, response, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.Authority;
|
||||||
|
import stirling.software.SPDF.model.User;
|
||||||
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CustomUserDetailsService implements UserDetailsService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
|
User user = userRepository.findByUsername(username)
|
||||||
|
.orElseThrow(() -> new UsernameNotFoundException("No user found with username: " + username));
|
||||||
|
|
||||||
|
return new org.springframework.security.core.userdetails.User(
|
||||||
|
user.getUsername(),
|
||||||
|
user.getPassword(),
|
||||||
|
user.isEnabled(),
|
||||||
|
true, true, true,
|
||||||
|
getAuthorities(user.getAuthorities())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<? extends GrantedAuthority> getAuthorities(Set<Authority> authorities) {
|
||||||
|
return authorities.stream()
|
||||||
|
.map(authority -> new SimpleGrantedAuthority(authority.getAuthority()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.Role;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class InitialSecuritySetup {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
if (!userService.hasUsers()) {
|
||||||
|
String initialUsername = applicationProperties.getSecurity().getInitialLogin().getUsername();
|
||||||
|
String initialPassword = applicationProperties.getSecurity().getInitialLogin().getPassword();
|
||||||
|
if (initialUsername != null && initialPassword != null) {
|
||||||
|
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void initSecretKey() throws IOException {
|
||||||
|
String secretKey = applicationProperties.getAutomaticallyGenerated().getKey();
|
||||||
|
if (secretKey == null || secretKey.isEmpty()) {
|
||||||
|
secretKey = UUID.randomUUID().toString(); // Generating a random UUID as the secret key
|
||||||
|
saveKeyToConfig(secretKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveKeyToConfig(String key) throws IOException {
|
||||||
|
Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml
|
||||||
|
List<String> lines = Files.readAllLines(path);
|
||||||
|
boolean keyFound = false;
|
||||||
|
|
||||||
|
// Search for the existing key to replace it or place to add it
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
if (lines.get(i).startsWith("AutomaticallyGenerated:")) {
|
||||||
|
keyFound = true;
|
||||||
|
if (i + 1 < lines.size() && lines.get(i + 1).trim().startsWith("key:")) {
|
||||||
|
lines.set(i + 1, " key: " + key);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
lines.add(i + 1, " key: " + key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the section doesn't exist, append it
|
||||||
|
if (!keyFound) {
|
||||||
|
lines.add("# Automatically Generated Settings (Do Not Edit Directly)");
|
||||||
|
lines.add("AutomaticallyGenerated:");
|
||||||
|
lines.add(" key: " + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write back to the file
|
||||||
|
Files.write(path, lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity()
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
@Autowired
|
||||||
|
@Lazy
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("loginEnabled")
|
||||||
|
public boolean loginEnabledValue;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserAuthenticationFilter userAuthenticationFilter;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
|
|
||||||
|
if(loginEnabledValue) {
|
||||||
|
|
||||||
|
http.csrf(csrf -> csrf.disable());
|
||||||
|
http
|
||||||
|
.formLogin(formLogin -> formLogin
|
||||||
|
.loginPage("/login")
|
||||||
|
.defaultSuccessUrl("/")
|
||||||
|
.failureHandler(new CustomAuthenticationFailureHandler())
|
||||||
|
.permitAll()
|
||||||
|
)
|
||||||
|
.logout(logout -> logout
|
||||||
|
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||||
|
.logoutSuccessUrl("/login?logout=true")
|
||||||
|
.invalidateHttpSession(true) // Invalidate session
|
||||||
|
.deleteCookies("JSESSIONID", "remember-me")
|
||||||
|
).rememberMe(rememberMeConfigurer -> rememberMeConfigurer // Use the configurator directly
|
||||||
|
.key("uniqueAndSecret")
|
||||||
|
.tokenRepository(persistentTokenRepository())
|
||||||
|
.tokenValiditySeconds(1209600) // 2 weeks
|
||||||
|
)
|
||||||
|
.authorizeHttpRequests(authz -> authz
|
||||||
|
.requestMatchers(req -> req.getRequestURI().startsWith("/login") || req.getRequestURI().endsWith(".svg") || req.getRequestURI().startsWith("/register") || req.getRequestURI().startsWith("/error") || req.getRequestURI().startsWith("/images/") || req.getRequestURI().startsWith("/public/") || req.getRequestURI().startsWith("/css/") || req.getRequestURI().startsWith("/js/"))
|
||||||
|
.permitAll()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
)
|
||||||
|
.userDetailsService(userDetailsService)
|
||||||
|
.authenticationProvider(authenticationProvider());
|
||||||
|
} else {
|
||||||
|
http.csrf(csrf -> csrf.disable())
|
||||||
|
.authorizeHttpRequests(authz -> authz
|
||||||
|
.anyRequest().permitAll()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DaoAuthenticationProvider authenticationProvider() {
|
||||||
|
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
|
||||||
|
authProvider.setUserDetailsService(userDetailsService);
|
||||||
|
authProvider.setPasswordEncoder(passwordEncoder());
|
||||||
|
return authProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PersistentTokenRepository persistentTokenRepository() {
|
||||||
|
return new JPATokenRepositoryImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
|
||||||
|
@Component
|
||||||
|
public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Lazy
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("loginEnabled")
|
||||||
|
public boolean loginEnabledValue;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
|
||||||
|
if (!loginEnabledValue) {
|
||||||
|
// If login is not enabled, just pass all requests without authentication
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
// Check for API key in the request headers if no authentication exists
|
||||||
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
|
String apiKey = request.getHeader("X-API-Key");
|
||||||
|
if (apiKey != null && !apiKey.trim().isEmpty()) {
|
||||||
|
try {
|
||||||
|
// Use API key to authenticate. This requires you to have an authentication provider for API keys.
|
||||||
|
UserDetails userDetails = userService.loadUserByApiKey(apiKey);
|
||||||
|
if(userDetails == null)
|
||||||
|
{
|
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
response.getWriter().write("Invalid API Key.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
authentication = new ApiKeyAuthenticationToken(userDetails, apiKey, userDetails.getAuthorities());
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
// If API key authentication fails, deny the request
|
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
response.getWriter().write("Invalid API Key.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we still don't have any authentication, deny the request
|
||||||
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
|
String method = request.getMethod();
|
||||||
|
if ("GET".equalsIgnoreCase(method)) {
|
||||||
|
response.sendRedirect("/login"); // redirect to the login page
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
response.getWriter().write("Authentication required. Please provide a X-API-KEY in request header.\nThis is found in Settings -> Account Settings -> API Key\nAlternativly you can disable authentication if this is unexpected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
|
||||||
|
String uri = request.getRequestURI();
|
||||||
|
|
||||||
|
String[] permitAllPatterns = {
|
||||||
|
"/login",
|
||||||
|
"/register",
|
||||||
|
"/error",
|
||||||
|
"/images/",
|
||||||
|
"/public/",
|
||||||
|
"/css/",
|
||||||
|
"/js/"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String pattern : permitAllPatterns) {
|
||||||
|
if (uri.startsWith(pattern) || uri.endsWith(".svg")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import io.github.bucket4j.Bandwidth;
|
||||||
|
import io.github.bucket4j.Bucket;
|
||||||
|
import io.github.bucket4j.ConsumptionProbe;
|
||||||
|
import io.github.bucket4j.Refill;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import stirling.software.SPDF.model.Role;
|
||||||
|
@Component
|
||||||
|
public class UserBasedRateLimitingFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final Map<String, Bucket> apiBuckets = new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, Bucket> webBuckets = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("rateLimit")
|
||||||
|
public boolean rateLimit;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
if (!rateLimit) {
|
||||||
|
// If rateLimit is not enabled, just pass all requests without rate limiting
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String method = request.getMethod();
|
||||||
|
if (!"POST".equalsIgnoreCase(method)) {
|
||||||
|
// If the request is not a POST, just pass it through without rate limiting
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String identifier = null;
|
||||||
|
|
||||||
|
// Check for API key in the request headers
|
||||||
|
String apiKey = request.getHeader("X-API-Key");
|
||||||
|
if (apiKey != null && !apiKey.trim().isEmpty()) {
|
||||||
|
identifier = "API_KEY_" + apiKey; // Prefix to distinguish between API keys and usernames
|
||||||
|
} else {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
|
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||||
|
identifier = userDetails.getUsername();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If neither API key nor an authenticated user is present, use IP address
|
||||||
|
if (identifier == null) {
|
||||||
|
identifier = request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
Role userRole = getRoleFromAuthentication(SecurityContextHolder.getContext().getAuthentication());
|
||||||
|
|
||||||
|
if (request.getHeader("X-API-Key") != null) {
|
||||||
|
// It's an API call
|
||||||
|
processRequest(userRole.getApiCallsPerDay(), identifier, apiBuckets, request, response, filterChain);
|
||||||
|
} else {
|
||||||
|
// It's a Web UI call
|
||||||
|
processRequest(userRole.getWebCallsPerDay(), identifier, webBuckets, request, response, filterChain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Role getRoleFromAuthentication(Authentication authentication) {
|
||||||
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
|
for (GrantedAuthority authority : authentication.getAuthorities()) {
|
||||||
|
try {
|
||||||
|
return Role.fromString(authority.getAuthority());
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// Ignore and continue to next authority.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("User does not have a valid role.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processRequest(int limitPerDay, String identifier, Map<String, Bucket> buckets,
|
||||||
|
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
Bucket userBucket = buckets.computeIfAbsent(identifier, k -> createUserBucket(limitPerDay));
|
||||||
|
ConsumptionProbe probe = userBucket.tryConsumeAndReturnRemaining(1);
|
||||||
|
|
||||||
|
if (probe.isConsumed()) {
|
||||||
|
response.setHeader("X-Rate-Limit-Remaining", Long.toString(probe.getRemainingTokens()));
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
} else {
|
||||||
|
long waitForRefill = probe.getNanosToWaitForRefill() / 1_000_000_000;
|
||||||
|
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
|
||||||
|
response.setHeader("X-Rate-Limit-Retry-After-Seconds", String.valueOf(waitForRefill));
|
||||||
|
response.getWriter().write("Rate limit exceeded for POST requests.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bucket createUserBucket(int limitPerDay) {
|
||||||
|
Bandwidth limit = Bandwidth.classic(limitPerDay, Refill.intervally(limitPerDay, Duration.ofDays(1)));
|
||||||
|
return Bucket.builder().addLimit(limit).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.Authority;
|
||||||
|
import stirling.software.SPDF.model.User;
|
||||||
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
|
@Service
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
public Authentication getAuthentication(String apiKey) {
|
||||||
|
User user = getUserByApiKey(apiKey);
|
||||||
|
if (user == null) {
|
||||||
|
throw new UsernameNotFoundException("API key is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the user into an Authentication object
|
||||||
|
return new UsernamePasswordAuthenticationToken(
|
||||||
|
user, // principal (typically the user)
|
||||||
|
null, // credentials (we don't expose the password or API key here)
|
||||||
|
getAuthorities(user) // user's authorities (roles/permissions)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<? extends GrantedAuthority> getAuthorities(User user) {
|
||||||
|
// Convert each Authority object into a SimpleGrantedAuthority object.
|
||||||
|
return user.getAuthorities().stream()
|
||||||
|
.map((Authority authority) -> new SimpleGrantedAuthority(authority.getAuthority()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateApiKey() {
|
||||||
|
String apiKey;
|
||||||
|
do {
|
||||||
|
apiKey = UUID.randomUUID().toString();
|
||||||
|
} while (userRepository.findByApiKey(apiKey) != null); // Ensure uniqueness
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User addApiKeyToUser(String username) {
|
||||||
|
User user = userRepository.findByUsername(username)
|
||||||
|
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||||
|
|
||||||
|
user.setApiKey(generateApiKey());
|
||||||
|
return userRepository.save(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User refreshApiKeyForUser(String username) {
|
||||||
|
return addApiKeyToUser(username); // reuse the add API key method for refreshing
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiKeyForUser(String username) {
|
||||||
|
User user = userRepository.findByUsername(username)
|
||||||
|
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||||
|
return user.getApiKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValidApiKey(String apiKey) {
|
||||||
|
return userRepository.findByApiKey(apiKey) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUserByApiKey(String apiKey) {
|
||||||
|
return userRepository.findByApiKey(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserDetails loadUserByApiKey(String apiKey) {
|
||||||
|
User userOptional = userRepository.findByApiKey(apiKey);
|
||||||
|
if (userOptional != null) {
|
||||||
|
User user = userOptional;
|
||||||
|
// Convert your User entity to a UserDetails object with authorities
|
||||||
|
return new org.springframework.security.core.userdetails.User(
|
||||||
|
user.getUsername(),
|
||||||
|
user.getPassword(), // you might not need this for API key auth
|
||||||
|
getAuthorities(user)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null; // or throw an exception
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean validateApiKeyForUser(String username, String apiKey) {
|
||||||
|
Optional<User> userOpt = userRepository.findByUsername(username);
|
||||||
|
return userOpt.isPresent() && userOpt.get().getApiKey().equals(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveUser(String username, String password) {
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername(username);
|
||||||
|
user.setPassword(passwordEncoder.encode(password));
|
||||||
|
user.setEnabled(true);
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveUser(String username, String password, String role) {
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername(username);
|
||||||
|
user.setPassword(passwordEncoder.encode(password));
|
||||||
|
user.addAuthority(new Authority(role, user));
|
||||||
|
user.setEnabled(true);
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteUser(String username) {
|
||||||
|
Optional<User> userOpt = userRepository.findByUsername(username);
|
||||||
|
if (userOpt.isPresent()) {
|
||||||
|
userRepository.delete(userOpt.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean usernameExists(String username) {
|
||||||
|
return userRepository.findByUsername(username).isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasUsers() {
|
||||||
|
return userRepository.count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateUserSettings(String username, Map<String, String> updates) {
|
||||||
|
Optional<User> userOpt = userRepository.findByUsername(username);
|
||||||
|
if (userOpt.isPresent()) {
|
||||||
|
User user = userOpt.get();
|
||||||
|
Map<String, String> settingsMap = user.getSettings();
|
||||||
|
|
||||||
|
if(settingsMap == null) {
|
||||||
|
settingsMap = new HashMap<String,String>();
|
||||||
|
}
|
||||||
|
settingsMap.clear();
|
||||||
|
settingsMap.putAll(updates);
|
||||||
|
user.setSettings(settingsMap);
|
||||||
|
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<User> findByUsername(String username) {
|
||||||
|
return userRepository.findByUsername(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeUsername(User user, String newUsername) {
|
||||||
|
user.setUsername(newUsername);
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changePassword(User user, String newPassword) {
|
||||||
|
user.setPassword(passwordEncoder.encode(newPassword));
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPasswordCorrect(User user, String currentPassword) {
|
||||||
|
return passwordEncoder.matches(currentPassword, user.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.itextpdf.kernel.geom.PageSize;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfPage;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfReader;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||||
|
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
|
||||||
|
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "General", description = "General APIs")
|
||||||
|
public class CropController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(CropController.class);
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping(value = "/crop", consumes = "multipart/form-data")
|
||||||
|
@Operation(summary = "Crops a PDF document", description = "This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> cropPdf(
|
||||||
|
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
||||||
|
@Parameter(description = "The x-coordinate of the top-left corner of the crop area", required = true, schema = @Schema(type = "number")) @RequestParam("x") float x,
|
||||||
|
@Parameter(description = "The y-coordinate of the top-left corner of the crop area", required = true, schema = @Schema(type = "number")) @RequestParam("y") float y,
|
||||||
|
@Parameter(description = "The width of the crop area", required = true, schema = @Schema(type = "number")) @RequestParam("width") float width,
|
||||||
|
@Parameter(description = "The height of the crop area", required = true, schema = @Schema(type = "number")) @RequestParam("height") float height) throws IOException {
|
||||||
|
byte[] bytes = file.getBytes();
|
||||||
|
System.out.println("x=" + x + ", " + "y=" + y + ", " + "width=" + width + ", " +"height=" + height );
|
||||||
|
PdfReader reader = new PdfReader(new ByteArrayInputStream(bytes));
|
||||||
|
PdfDocument pdfDoc = new PdfDocument(reader);
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
PdfWriter writer = new PdfWriter(baos);
|
||||||
|
PdfDocument outputPdf = new PdfDocument(writer);
|
||||||
|
|
||||||
|
int totalPages = pdfDoc.getNumberOfPages();
|
||||||
|
|
||||||
|
for (int i = 1; i <= totalPages; i++) {
|
||||||
|
PdfPage page = outputPdf.addNewPage(new PageSize(width, height));
|
||||||
|
PdfCanvas pdfCanvas = new PdfCanvas(page);
|
||||||
|
|
||||||
|
PdfFormXObject formXObject = pdfDoc.getPage(i).copyAsFormXObject(outputPdf);
|
||||||
|
|
||||||
|
// Save the graphics state, apply the transformations, add the object, and then
|
||||||
|
// restore the graphics state
|
||||||
|
pdfCanvas.saveState();
|
||||||
|
pdfCanvas.rectangle(x, y, width, height);
|
||||||
|
pdfCanvas.clip();
|
||||||
|
pdfCanvas.addXObject(formXObject, -x, -y);
|
||||||
|
pdfCanvas.restoreState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
outputPdf.close();
|
||||||
|
byte[] pdfContent = baos.toByteArray();
|
||||||
|
pdfDoc.close();
|
||||||
|
return WebResponseUtils.bytesToWebResponse(pdfContent,
|
||||||
|
file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_cropped.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,22 +1,29 @@
|
|||||||
package stirling.software.SPDF.controller.api;
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RequestPart;
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@@ -26,55 +33,93 @@ public class MergeController {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
|
private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
|
||||||
|
|
||||||
private PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
|
|
||||||
// Create a new empty document
|
|
||||||
PDDocument mergedDoc = new PDDocument();
|
|
||||||
|
|
||||||
// Iterate over the list of documents and add their pages to the merged document
|
|
||||||
for (PDDocument doc : documents) {
|
|
||||||
// Get all pages from the current document
|
|
||||||
PDPageTree pages = doc.getPages();
|
|
||||||
// Iterate over the pages and add them to the merged document
|
|
||||||
for (PDPage page : pages) {
|
|
||||||
mergedDoc.addPage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
private PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
|
||||||
|
PDDocument mergedDoc = new PDDocument();
|
||||||
|
for (PDDocument doc : documents) {
|
||||||
|
for (PDPage page : doc.getPages()) {
|
||||||
|
mergedDoc.addPage(page);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return mergedDoc;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the merged document
|
private Comparator<MultipartFile> getSortComparator(String sortType) {
|
||||||
return mergedDoc;
|
switch (sortType) {
|
||||||
|
case "byFileName":
|
||||||
|
return Comparator.comparing(MultipartFile::getOriginalFilename);
|
||||||
|
case "byDateModified":
|
||||||
|
return (file1, file2) -> {
|
||||||
|
try {
|
||||||
|
BasicFileAttributes attr1 = Files.readAttributes(Paths.get(file1.getOriginalFilename()), BasicFileAttributes.class);
|
||||||
|
BasicFileAttributes attr2 = Files.readAttributes(Paths.get(file2.getOriginalFilename()), BasicFileAttributes.class);
|
||||||
|
return attr1.lastModifiedTime().compareTo(attr2.lastModifiedTime());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return 0; // If there's an error, treat them as equal
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case "byDateCreated":
|
||||||
|
return (file1, file2) -> {
|
||||||
|
try {
|
||||||
|
BasicFileAttributes attr1 = Files.readAttributes(Paths.get(file1.getOriginalFilename()), BasicFileAttributes.class);
|
||||||
|
BasicFileAttributes attr2 = Files.readAttributes(Paths.get(file2.getOriginalFilename()), BasicFileAttributes.class);
|
||||||
|
return attr1.creationTime().compareTo(attr2.creationTime());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return 0; // If there's an error, treat them as equal
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case "byPDFTitle":
|
||||||
|
return (file1, file2) -> {
|
||||||
|
try (PDDocument doc1 = PDDocument.load(file1.getInputStream());
|
||||||
|
PDDocument doc2 = PDDocument.load(file2.getInputStream())) {
|
||||||
|
String title1 = doc1.getDocumentInformation().getTitle();
|
||||||
|
String title2 = doc2.getDocumentInformation().getTitle();
|
||||||
|
return title1.compareTo(title2);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case "orderProvided":
|
||||||
|
default:
|
||||||
|
return (file1, file2) -> 0; // Default is the order provided
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
|
||||||
|
@Operation(summary = "Merge multiple PDF files into one",
|
||||||
|
description = "This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided. Input:PDF Output:PDF Type:MISO")
|
||||||
|
public ResponseEntity<byte[]> mergePdfs(
|
||||||
|
@RequestPart(required = true, value = "fileInput") MultipartFile[] files,
|
||||||
|
@RequestParam(value = "sortType", defaultValue = "orderProvided")
|
||||||
|
@Parameter(schema = @Schema(description = "The type of sorting to be applied on the input files before merging.",
|
||||||
|
allowableValues = {
|
||||||
|
"orderProvided",
|
||||||
|
"byFileName",
|
||||||
|
"byDateModified",
|
||||||
|
"byDateCreated",
|
||||||
|
"byPDFTitle"
|
||||||
|
}))
|
||||||
|
String sortType) throws IOException {
|
||||||
|
|
||||||
|
Arrays.sort(files, getSortComparator(sortType));
|
||||||
|
|
||||||
|
List<PDDocument> documents = new ArrayList<>();
|
||||||
|
for (MultipartFile file : files) {
|
||||||
|
try (InputStream is = file.getInputStream()) {
|
||||||
|
documents.add(PDDocument.load(is));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
|
try (PDDocument mergedDoc = mergeDocuments(documents)) {
|
||||||
@Operation(
|
|
||||||
summary = "Merge multiple PDF files into one",
|
|
||||||
description = "This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided. Input:PDF Output:PDF Type:MISO"
|
|
||||||
)
|
|
||||||
public ResponseEntity<byte[]> mergePdfs(
|
|
||||||
@RequestPart(required = true, value = "fileInput")
|
|
||||||
@Parameter(description = "The input PDF files to be merged into a single file", required = true)
|
|
||||||
MultipartFile[] files) throws IOException {
|
|
||||||
// Read the input PDF files into PDDocument objects
|
|
||||||
List<PDDocument> documents = new ArrayList<>();
|
|
||||||
|
|
||||||
// Loop through the files array and read each file into a PDDocument
|
|
||||||
for (MultipartFile file : files) {
|
|
||||||
documents.add(PDDocument.load(file.getInputStream()));
|
|
||||||
}
|
|
||||||
|
|
||||||
PDDocument mergedDoc = mergeDocuments(documents);
|
|
||||||
|
|
||||||
|
|
||||||
// Return the merged PDF as a response
|
|
||||||
ResponseEntity<byte[]> response = WebResponseUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
|
ResponseEntity<byte[]> response = WebResponseUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
|
||||||
|
|
||||||
for (PDDocument doc : documents) {
|
|
||||||
// Close the document after processing
|
|
||||||
doc.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
} finally {
|
||||||
|
for (PDDocument doc : documents) {
|
||||||
|
if (doc != null) {
|
||||||
|
doc.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -52,11 +52,11 @@ public class ScalePagesController {
|
|||||||
@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> scalePages(
|
public ResponseEntity<byte[]> scalePages(
|
||||||
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
||||||
@Parameter(description = "The scale of pages in the output PDF. Acceptable values are A0-A10, B0-B9, LETTER, TABLOID, LEDGER, LEGAL, EXECUTIVE.", required = true, schema = @Schema(type = "String", allowableValues = {
|
@Parameter(description = "The scale of pages in the output PDF. Acceptable values are A0-A10, B0-B9, LETTER, TABLOID, LEDGER, LEGAL, EXECUTIVE.", required = true, schema = @Schema(type = "string", allowableValues = {
|
||||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "B0", "B1", "B2", "B3", "B4",
|
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "B0", "B1", "B2", "B3", "B4",
|
||||||
"B5", "B6", "B7", "B8", "B9", "LETTER", "TABLOID", "LEDGER", "LEGAL",
|
"B5", "B6", "B7", "B8", "B9", "LETTER", "TABLOID", "LEDGER", "LEGAL",
|
||||||
"EXECUTIVE" })) @RequestParam("pageSize") String targetPageSize,
|
"EXECUTIVE" })) @RequestParam("pageSize") String targetPageSize,
|
||||||
@Parameter(description = "The scale of the content on the pages of the output PDF. Acceptable values are floats.", required = true, schema = @Schema(type = "float")) @RequestParam("scaleFactor") float scaleFactor)
|
@Parameter(description = "The scale of the content on the pages of the output PDF. Acceptable values are floats.", required = true, schema = @Schema(type = "integer")) @RequestParam("scaleFactor") float scaleFactor)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
Map<String, PageSize> sizeMap = new HashMap<>();
|
Map<String, PageSize> sizeMap = new HashMap<>();
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.itextpdf.kernel.geom.PageSize;
|
||||||
|
import com.itextpdf.kernel.geom.Rectangle;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfReader;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||||
|
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
|
||||||
|
import com.itextpdf.layout.Document;
|
||||||
|
import com.itextpdf.layout.element.Image;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "General", description = "General APIs")
|
||||||
|
public class ToSinglePageController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ToSinglePageController.class);
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
|
||||||
|
@Operation(
|
||||||
|
summary = "Convert a multi-page PDF into a single long page PDF",
|
||||||
|
description = "This endpoint converts a multi-page PDF document into a single paged PDF document. The width of the single page will be same as the input's width, but the height will be the sum of all the pages' heights. Input:PDF Output:PDF Type:SISO"
|
||||||
|
)
|
||||||
|
public ResponseEntity<byte[]> pdfToSinglePage(
|
||||||
|
@RequestPart(required = true, value = "fileInput")
|
||||||
|
@Parameter(description = "The input multi-page PDF file to be converted into a single page", required = true)
|
||||||
|
MultipartFile file) throws IOException {
|
||||||
|
|
||||||
|
PdfReader reader = new PdfReader(file.getInputStream());
|
||||||
|
PdfDocument sourceDocument = new PdfDocument(reader);
|
||||||
|
|
||||||
|
float totalHeight = 0;
|
||||||
|
float width = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i <= sourceDocument.getNumberOfPages(); i++) {
|
||||||
|
Rectangle pageSize = sourceDocument.getPage(i).getPageSize();
|
||||||
|
totalHeight += pageSize.getHeight();
|
||||||
|
if(width < pageSize.getWidth())
|
||||||
|
width = pageSize.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
PdfWriter writer = new PdfWriter(baos);
|
||||||
|
PdfDocument newDocument = new PdfDocument(writer);
|
||||||
|
PageSize newPageSize = new PageSize(width, totalHeight);
|
||||||
|
newDocument.addNewPage(newPageSize);
|
||||||
|
|
||||||
|
Document layoutDoc = new Document(newDocument);
|
||||||
|
float yOffset = totalHeight;
|
||||||
|
|
||||||
|
for (int i = 1; i <= sourceDocument.getNumberOfPages(); i++) {
|
||||||
|
PdfFormXObject pageCopy = sourceDocument.getPage(i).copyAsFormXObject(newDocument);
|
||||||
|
Image copiedPage = new Image(pageCopy);
|
||||||
|
copiedPage.setFixedPosition(0, yOffset - sourceDocument.getPage(i).getPageSize().getHeight());
|
||||||
|
yOffset -= sourceDocument.getPage(i).getPageSize().getHeight();
|
||||||
|
layoutDoc.add(copiedPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutDoc.close();
|
||||||
|
sourceDocument.close();
|
||||||
|
|
||||||
|
byte[] result = baos.toByteArray();
|
||||||
|
return WebResponseUtils.bytesToWebResponse(result, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_singlePage.pdf");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
|
import stirling.software.SPDF.model.User;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@PostMapping("/register")
|
||||||
|
public String register(@RequestParam String username, @RequestParam String password, Model model) {
|
||||||
|
if(userService.usernameExists(username)) {
|
||||||
|
model.addAttribute("error", "Username already exists");
|
||||||
|
return "register";
|
||||||
|
}
|
||||||
|
|
||||||
|
userService.saveUser(username, password);
|
||||||
|
return "redirect:/login?registered=true";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/change-username")
|
||||||
|
public ResponseEntity<String> changeUsername(Principal principal, @RequestParam String currentPassword, @RequestParam String newUsername, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
if (principal == null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User not authenticated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<User> userOpt = userService.findByUsername(principal.getName());
|
||||||
|
|
||||||
|
if(userOpt == null || userOpt.isEmpty()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found.");
|
||||||
|
}
|
||||||
|
User user = userOpt.get();
|
||||||
|
|
||||||
|
if(!userService.isPasswordCorrect(user, currentPassword)) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Current password is incorrect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(userService.usernameExists(newUsername)) {
|
||||||
|
return ResponseEntity.status(HttpStatus.CONFLICT).body("New username already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
userService.changeUsername(user, newUsername);
|
||||||
|
|
||||||
|
// Logout using Spring's utility
|
||||||
|
new SecurityContextLogoutHandler().logout(request, response, null);
|
||||||
|
|
||||||
|
|
||||||
|
return ResponseEntity.ok("Username updated successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/change-password")
|
||||||
|
public ResponseEntity<String> changePassword(Principal principal, @RequestParam String currentPassword, @RequestParam String newPassword, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
if (principal == null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User not authenticated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<User> userOpt = userService.findByUsername(principal.getName());
|
||||||
|
|
||||||
|
if(userOpt == null || userOpt.isEmpty()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found.");
|
||||||
|
}
|
||||||
|
User user = userOpt.get();
|
||||||
|
if(!userService.isPasswordCorrect(user, currentPassword)) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Current password is incorrect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
userService.changePassword(user, newPassword);
|
||||||
|
|
||||||
|
// Logout using Spring's utility
|
||||||
|
new SecurityContextLogoutHandler().logout(request, response, null);
|
||||||
|
|
||||||
|
return ResponseEntity.ok("Password updated successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/updateUserSettings")
|
||||||
|
public String updateUserSettings(HttpServletRequest request, Principal principal) {
|
||||||
|
Map<String, String[]> paramMap = request.getParameterMap();
|
||||||
|
Map<String, String> updates = new HashMap<>();
|
||||||
|
|
||||||
|
System.out.println("Received parameter map: " + paramMap);
|
||||||
|
|
||||||
|
for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
|
||||||
|
updates.put(entry.getKey(), entry.getValue()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Processed updates: " + updates);
|
||||||
|
|
||||||
|
// Assuming you have a method in userService to update the settings for a user
|
||||||
|
userService.updateUserSettings(principal.getName(), updates);
|
||||||
|
|
||||||
|
return "redirect:/account"; // Redirect to a page of your choice after updating
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
|
@PostMapping("/admin/saveUser")
|
||||||
|
public String saveUser(@RequestParam String username, @RequestParam String password, @RequestParam String role) {
|
||||||
|
userService.saveUser(username, password, role);
|
||||||
|
return "redirect:/addUsers"; // Redirect to account page after adding the user
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
|
@GetMapping("/admin/deleteUser/{username}")
|
||||||
|
public String deleteUser(@PathVariable String username) {
|
||||||
|
userService.deleteUser(username);
|
||||||
|
return "redirect:/addUsers";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/get-api-key")
|
||||||
|
public ResponseEntity<String> getApiKey(Principal principal) {
|
||||||
|
if (principal == null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User not authenticated.");
|
||||||
|
}
|
||||||
|
String username = principal.getName();
|
||||||
|
String apiKey = userService.getApiKeyForUser(username);
|
||||||
|
if (apiKey == null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("API key not found for user.");
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update-api-key")
|
||||||
|
public ResponseEntity<String> updateApiKey(Principal principal) {
|
||||||
|
if (principal == null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User not authenticated.");
|
||||||
|
}
|
||||||
|
String username = principal.getName();
|
||||||
|
User user = userService.refreshApiKeyForUser(username);
|
||||||
|
String apiKey = user.getApiKey();
|
||||||
|
if (apiKey == null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("API key not found for user.");
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
public class ConvertEpubToPdf {
|
||||||
|
//TODO
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/epub-to-single-pdf")
|
||||||
|
@Hidden
|
||||||
|
@Operation(
|
||||||
|
summary = "Convert an EPUB file to a single PDF",
|
||||||
|
description = "This endpoint takes an EPUB file input and converts it to a single PDF."
|
||||||
|
)
|
||||||
|
public ResponseEntity<byte[]> epubToSinglePdf(
|
||||||
|
@RequestPart(required = true, value = "fileInput") MultipartFile fileInput)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
if (fileInput == null) {
|
||||||
|
throw new IllegalArgumentException("Please provide an EPUB file for conversion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String originalFilename = fileInput.getOriginalFilename();
|
||||||
|
if (originalFilename == null || !originalFilename.endsWith(".epub")) {
|
||||||
|
throw new IllegalArgumentException("File must be in .epub format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, byte[]> epubContents = extractEpubContent(fileInput);
|
||||||
|
List<String> htmlFilesOrder = getHtmlFilesOrderFromOpf(epubContents);
|
||||||
|
|
||||||
|
List<byte[]> individualPdfs = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String htmlFile : htmlFilesOrder) {
|
||||||
|
byte[] htmlContent = epubContents.get(htmlFile);
|
||||||
|
byte[] pdfBytes = FileToPdf.convertHtmlToPdf(htmlContent, htmlFile.replace(".html", ".pdf"));
|
||||||
|
individualPdfs.add(pdfBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pseudo-code to merge individual PDFs into one.
|
||||||
|
byte[] mergedPdfBytes = mergeMultiplePdfsIntoOne(individualPdfs);
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(mergedPdfBytes, originalFilename.replace(".epub", ".pdf"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming a pseudo-code function that merges multiple PDFs into one.
|
||||||
|
private byte[] mergeMultiplePdfsIntoOne(List<byte[]> individualPdfs) {
|
||||||
|
// You can use a library such as iText or PDFBox to perform the merging here.
|
||||||
|
// Return the byte[] of the merged PDF.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, byte[]> extractEpubContent(MultipartFile fileInput) throws IOException {
|
||||||
|
Map<String, byte[]> contentMap = new HashMap<>();
|
||||||
|
|
||||||
|
try (ZipInputStream zis = new ZipInputStream(fileInput.getInputStream())) {
|
||||||
|
ZipEntry zipEntry = zis.getNextEntry();
|
||||||
|
while (zipEntry != null) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read = 0;
|
||||||
|
while ((read = zis.read(buffer)) != -1) {
|
||||||
|
baos.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
contentMap.put(zipEntry.getName(), baos.toByteArray());
|
||||||
|
zipEntry = zis.getNextEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contentMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getHtmlFilesOrderFromOpf(Map<String, byte[]> epubContents) throws Exception {
|
||||||
|
String opfContent = new String(epubContents.get("OEBPS/content.opf")); // Adjusting for given path
|
||||||
|
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||||
|
InputSource is = new InputSource(new StringReader(opfContent));
|
||||||
|
Document doc = dBuilder.parse(is);
|
||||||
|
|
||||||
|
NodeList itemRefs = doc.getElementsByTagName("itemref");
|
||||||
|
List<String> htmlFilesOrder = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < itemRefs.getLength(); i++) {
|
||||||
|
Element itemRef = (Element) itemRefs.item(i);
|
||||||
|
String idref = itemRef.getAttribute("idref");
|
||||||
|
|
||||||
|
NodeList items = doc.getElementsByTagName("item");
|
||||||
|
for (int j = 0; j < items.getLength(); j++) {
|
||||||
|
Element item = (Element) items.item(j);
|
||||||
|
if (idref.equals(item.getAttribute("id"))) {
|
||||||
|
htmlFilesOrder.add(item.getAttribute("href")); // Fetching the actual href
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlFilesOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
public class ConvertHtmlToPDF {
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/html-to-pdf")
|
||||||
|
@Operation(
|
||||||
|
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
|
||||||
|
description = "This endpoint takes an HTML or ZIP file input and converts it to a PDF format."
|
||||||
|
)
|
||||||
|
public ResponseEntity<byte[]> HtmlToPdf(
|
||||||
|
@RequestPart(required = true, value = "fileInput") MultipartFile fileInput) throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
if (fileInput == null) {
|
||||||
|
throw new IllegalArgumentException("Please provide an HTML or ZIP file for conversion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String originalFilename = fileInput.getOriginalFilename();
|
||||||
|
if (originalFilename == null || (!originalFilename.endsWith(".html") && !originalFilename.endsWith(".zip"))) {
|
||||||
|
throw new IllegalArgumentException("File must be either .html or .zip format.");
|
||||||
|
}byte[] pdfBytes = FileToPdf.convertHtmlToPdf( fileInput.getBytes(), originalFilename);
|
||||||
|
|
||||||
|
String outputFilename = originalFilename.replaceFirst("[.][^.]+$", "") + ".pdf"; // Remove file extension and append .pdf
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ public class ConvertImgPDFController {
|
|||||||
@Parameter(description = "Choose between a single image containing all pages or separate images for each page", schema = @Schema(allowableValues = {"single", "multiple"}))
|
@Parameter(description = "Choose between a single image containing all pages or separate images for each page", schema = @Schema(allowableValues = {"single", "multiple"}))
|
||||||
String singleOrMultiple,
|
String singleOrMultiple,
|
||||||
@RequestParam("colorType")
|
@RequestParam("colorType")
|
||||||
@Parameter(description = "The color type of the output image(s)", schema = @Schema(allowableValues = {"rgb", "greyscale", "blackwhite"}))
|
@Parameter(description = "The color type of the output image(s)", schema = @Schema(allowableValues = {"color", "greyscale", "blackwhite"}))
|
||||||
String colorType,
|
String colorType,
|
||||||
@RequestParam("dpi")
|
@RequestParam("dpi")
|
||||||
@Parameter(description = "The DPI (dots per inch) for the output image(s)")
|
@Parameter(description = "The DPI (dots per inch) for the output image(s)")
|
||||||
@@ -94,7 +94,7 @@ public class ConvertImgPDFController {
|
|||||||
@Parameter(description = "Whether to stretch the images to fit the PDF page or maintain the aspect ratio", example = "false")
|
@Parameter(description = "Whether to stretch the images to fit the PDF page or maintain the aspect ratio", example = "false")
|
||||||
boolean stretchToFit,
|
boolean stretchToFit,
|
||||||
@RequestParam("colorType")
|
@RequestParam("colorType")
|
||||||
@Parameter(description = "The color type of the output image(s)", schema = @Schema(allowableValues = {"rgb", "greyscale", "blackwhite"}))
|
@Parameter(description = "The color type of the output image(s)", schema = @Schema(allowableValues = {"color", "greyscale", "blackwhite"}))
|
||||||
String colorType,
|
String colorType,
|
||||||
@RequestParam(defaultValue = "false", name = "autoRotate")
|
@RequestParam(defaultValue = "false", name = "autoRotate")
|
||||||
@Parameter(description = "Whether to automatically rotate the images to better fit the PDF page", example = "true")
|
@Parameter(description = "Whether to automatically rotate the images to better fit the PDF page", example = "true")
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
import org.commonmark.renderer.html.HtmlRenderer;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
public class ConvertMarkdownToPdf {
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/markdown-to-pdf")
|
||||||
|
@Operation(
|
||||||
|
summary = "Convert a Markdown file to PDF",
|
||||||
|
description = "This endpoint takes a Markdown file input, converts it to HTML, and then to PDF format."
|
||||||
|
)
|
||||||
|
public ResponseEntity<byte[]> markdownToPdf(
|
||||||
|
@RequestPart(required = true, value = "fileInput") MultipartFile fileInput)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
if (fileInput == null) {
|
||||||
|
throw new IllegalArgumentException("Please provide a Markdown file for conversion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String originalFilename = fileInput.getOriginalFilename();
|
||||||
|
if (originalFilename == null || !originalFilename.endsWith(".md")) {
|
||||||
|
throw new IllegalArgumentException("File must be in .md format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Markdown to HTML using CommonMark
|
||||||
|
Parser parser = Parser.builder().build();
|
||||||
|
Node document = parser.parse(new String(fileInput.getBytes()));
|
||||||
|
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
||||||
|
String htmlContent = renderer.render(document);
|
||||||
|
|
||||||
|
byte[] pdfBytes = FileToPdf.convertHtmlToPdf(htmlContent.getBytes(), "converted.html");
|
||||||
|
|
||||||
|
String outputFilename = originalFilename.replaceFirst("[.][^.]+$", "") + ".pdf"; // Remove file extension and append .pdf
|
||||||
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -41,7 +42,7 @@ public class ConvertOfficeController {
|
|||||||
|
|
||||||
// Run the LibreOffice command
|
// Run the LibreOffice command
|
||||||
List<String> command = new ArrayList<>(Arrays.asList("unoconv", "-vvv", "-f", "pdf", "-o", tempOutputFile.toString(), tempInputFile.toString()));
|
List<String> command = new ArrayList<>(Arrays.asList("unoconv", "-vvv", "-f", "pdf", "-o", tempOutputFile.toString(), tempInputFile.toString()));
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command);
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the converted PDF file
|
// Read the converted PDF file
|
||||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
@@ -62,10 +63,10 @@ public class ConvertOfficeController {
|
|||||||
summary = "Convert a file to a PDF using LibreOffice",
|
summary = "Convert a file to a PDF using LibreOffice",
|
||||||
description = "This endpoint converts a given file to a PDF using LibreOffice API Input:Any Output:PDF Type:SISO"
|
description = "This endpoint converts a given file to a PDF using LibreOffice API Input:Any Output:PDF Type:SISO"
|
||||||
)
|
)
|
||||||
public ResponseEntity<byte[]> processPdfWithOCR(
|
public ResponseEntity<byte[]> processFileToPDF(
|
||||||
@RequestPart(required = true, value = "fileInput")
|
@RequestPart(required = true, value = "fileInput")
|
||||||
@Parameter(
|
@Parameter(
|
||||||
description = "The input file to be converted to a PDF file using OCR",
|
description = "The input file to be converted to a PDF file using LibreOffice",
|
||||||
required = true
|
required = true
|
||||||
)
|
)
|
||||||
MultipartFile inputFile
|
MultipartFile inputFile
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -49,7 +50,7 @@ public class ConvertPDFToPDFA {
|
|||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the optimized PDF file
|
// Read the optimized PDF file
|
||||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
public class ConvertWebsiteToPDF {
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/url-to-pdf")
|
||||||
|
@Operation(
|
||||||
|
summary = "Convert a URL to a PDF",
|
||||||
|
description = "This endpoint fetches content from a URL and converts it to a PDF format."
|
||||||
|
)
|
||||||
|
public ResponseEntity<byte[]> urlToPdf(
|
||||||
|
@RequestParam(required = true, value = "urlInput")
|
||||||
|
@Parameter(description = "The input URL to be converted to a PDF file", required = true)
|
||||||
|
String URL) throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
// Validate the URL format
|
||||||
|
if(!URL.matches("^https?://.*") || !GeneralUtils.isValidURL(URL)) {
|
||||||
|
throw new IllegalArgumentException("Invalid URL format provided.");
|
||||||
|
}
|
||||||
|
Path tempOutputFile = null;
|
||||||
|
byte[] pdfBytes;
|
||||||
|
try {
|
||||||
|
// Prepare the output file path
|
||||||
|
tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
|
|
||||||
|
// Prepare the OCRmyPDF command
|
||||||
|
List<String> command = new ArrayList<>();
|
||||||
|
command.add("weasyprint");
|
||||||
|
command.add(URL);
|
||||||
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
|
// Read the optimized PDF file
|
||||||
|
pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Clean up the temporary files
|
||||||
|
Files.delete(tempOutputFile);
|
||||||
|
}
|
||||||
|
// Convert URL to a safe filename
|
||||||
|
String outputFilename = convertURLToFileName(URL);
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertURLToFileName(String url) {
|
||||||
|
String safeName = url.replaceAll("[^a-zA-Z0-9]", "_");
|
||||||
|
if(safeName.length() > 50) {
|
||||||
|
safeName = safeName.substring(0, 50); // restrict to 50 characters
|
||||||
|
}
|
||||||
|
return safeName + ".pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller.api.filters;
|
package stirling.software.SPDF.controller.api.filters;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
@@ -17,67 +13,82 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "Filter", description = "Filter APIs")
|
@Tag(name = "Filter", description = "Filter APIs")
|
||||||
public class FilterController {
|
public class FilterController {
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/contains-text")
|
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-text")
|
||||||
@Operation(summary = "Checks if a PDF contains set text, returns true if does", description = "Input:PDF Output:Boolean Type:SISO")
|
@Operation(summary = "Checks if a PDF contains set text, returns true if does", description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
public Boolean containsText(
|
public ResponseEntity<byte[]> containsText(
|
||||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
|
||||||
@Parameter(description = "The text to check for", required = true) String text,
|
@Parameter(description = "The text to check for", required = true) String text,
|
||||||
@Parameter(description = "The page number to check for text on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
|
@Parameter(description = "The page number to check for text on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
||||||
return PdfUtils.hasText(pdfDocument, pageNumber);
|
if (PdfUtils.hasText(pdfDocument, pageNumber, text))
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(pdfDocument, inputFile.getOriginalFilename());
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/contains-image")
|
// TODO
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-image")
|
||||||
@Operation(summary = "Checks if a PDF contains an image", description = "Input:PDF Output:Boolean Type:SISO")
|
@Operation(summary = "Checks if a PDF contains an image", description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
public Boolean containsImage(
|
public ResponseEntity<byte[]> containsImage(
|
||||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
|
||||||
@Parameter(description = "The page number to check for image on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
|
@Parameter(description = "The page number to check for image on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
||||||
return PdfUtils.hasImagesOnPage(null);
|
if (PdfUtils.hasImages(pdfDocument, pageNumber))
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(pdfDocument, inputFile.getOriginalFilename());
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/page-count")
|
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-count")
|
||||||
@Operation(summary = "Checks if a PDF is greater, less or equal to a setPageCount", description = "Input:PDF Output:Boolean Type:SISO")
|
@Operation(summary = "Checks if a PDF is greater, less or equal to a setPageCount", description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
public Boolean pageCount(
|
public ResponseEntity<byte[]> pageCount(
|
||||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||||
@Parameter(description = "Page Count", required = true) String pageCount,
|
@Parameter(description = "Page Count", required = true) String pageCount,
|
||||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
@Parameter(description = "Comparison type", schema = @Schema(description = "The comparison type, accepts Greater, Equal, Less than", allowableValues = {
|
||||||
|
"Greater", "Equal", "Less" })) String comparator)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
// Load the PDF
|
// Load the PDF
|
||||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
||||||
int actualPageCount = document.getNumberOfPages();
|
int actualPageCount = document.getNumberOfPages();
|
||||||
|
|
||||||
|
boolean valid = false;
|
||||||
// Perform the comparison
|
// Perform the comparison
|
||||||
switch (comparator) {
|
switch (comparator) {
|
||||||
case "Greater":
|
case "Greater":
|
||||||
return actualPageCount > Integer.parseInt(pageCount);
|
valid = actualPageCount > Integer.parseInt(pageCount);
|
||||||
|
break;
|
||||||
case "Equal":
|
case "Equal":
|
||||||
return actualPageCount == Integer.parseInt(pageCount);
|
valid = actualPageCount == Integer.parseInt(pageCount);
|
||||||
|
break;
|
||||||
case "Less":
|
case "Less":
|
||||||
return actualPageCount < Integer.parseInt(pageCount);
|
valid = actualPageCount < Integer.parseInt(pageCount);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
return WebResponseUtils.multiPartFileToWebResponse(inputFile);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/page-size")
|
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-size")
|
||||||
@Operation(summary = "Checks if a PDF is of a certain size", description = "Input:PDF Output:Boolean Type:SISO")
|
@Operation(summary = "Checks if a PDF is of a certain size", description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
public Boolean pageSize(
|
public ResponseEntity<byte[]> pageSize(
|
||||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||||
@Parameter(description = "Standard Page Size", required = true) String standardPageSize,
|
@Parameter(description = "Standard Page Size", required = true) String standardPageSize,
|
||||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
@Parameter(description = "Comparison type", schema = @Schema(description = "The comparison type, accepts Greater, Equal, Less than", allowableValues = {
|
||||||
throws IOException, InterruptedException {
|
"Greater", "Equal", "Less" })) String comparator)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
// Load the PDF
|
// Load the PDF
|
||||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
||||||
@@ -92,52 +103,68 @@ public class FilterController {
|
|||||||
PDRectangle standardSize = PdfUtils.textToPageSize(standardPageSize);
|
PDRectangle standardSize = PdfUtils.textToPageSize(standardPageSize);
|
||||||
float standardArea = standardSize.getWidth() * standardSize.getHeight();
|
float standardArea = standardSize.getWidth() * standardSize.getHeight();
|
||||||
|
|
||||||
|
boolean valid = false;
|
||||||
// Perform the comparison
|
// Perform the comparison
|
||||||
switch (comparator) {
|
switch (comparator) {
|
||||||
case "Greater":
|
case "Greater":
|
||||||
return actualArea > standardArea;
|
valid = actualArea > standardArea;
|
||||||
|
break;
|
||||||
case "Equal":
|
case "Equal":
|
||||||
return actualArea == standardArea;
|
valid = actualArea == standardArea;
|
||||||
|
break;
|
||||||
case "Less":
|
case "Less":
|
||||||
return actualArea < standardArea;
|
valid = actualArea < standardArea;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
return WebResponseUtils.multiPartFileToWebResponse(inputFile);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/filter-file-size")
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/file-size")
|
|
||||||
@Operation(summary = "Checks if a PDF is a set file size", description = "Input:PDF Output:Boolean Type:SISO")
|
@Operation(summary = "Checks if a PDF is a set file size", description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
public Boolean fileSize(
|
public ResponseEntity<byte[]> fileSize(
|
||||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||||
@Parameter(description = "File Size", required = true) String fileSize,
|
@Parameter(description = "File Size", required = true) String fileSize,
|
||||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
@Parameter(description = "Comparison type", schema = @Schema(description = "The comparison type, accepts Greater, Equal, Less than", allowableValues = {
|
||||||
throws IOException, InterruptedException {
|
"Greater", "Equal", "Less" })) String comparator)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
// Get the file size
|
// Get the file size
|
||||||
long actualFileSize = inputFile.getSize();
|
long actualFileSize = inputFile.getSize();
|
||||||
|
|
||||||
|
boolean valid = false;
|
||||||
// Perform the comparison
|
// Perform the comparison
|
||||||
switch (comparator) {
|
switch (comparator) {
|
||||||
case "Greater":
|
case "Greater":
|
||||||
return actualFileSize > Long.parseLong(fileSize);
|
valid = actualFileSize > Long.parseLong(fileSize);
|
||||||
|
break;
|
||||||
case "Equal":
|
case "Equal":
|
||||||
return actualFileSize == Long.parseLong(fileSize);
|
valid = actualFileSize == Long.parseLong(fileSize);
|
||||||
|
break;
|
||||||
case "Less":
|
case "Less":
|
||||||
return actualFileSize < Long.parseLong(fileSize);
|
valid = actualFileSize < Long.parseLong(fileSize);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
return WebResponseUtils.multiPartFileToWebResponse(inputFile);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-rotation")
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/page-rotation")
|
|
||||||
@Operation(summary = "Checks if a PDF is of a certain rotation", description = "Input:PDF Output:Boolean Type:SISO")
|
@Operation(summary = "Checks if a PDF is of a certain rotation", description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
public Boolean pageRotation(
|
public ResponseEntity<byte[]> pageRotation(
|
||||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||||
@Parameter(description = "Rotation in degrees", required = true) int rotation,
|
@Parameter(description = "Rotation in degrees", required = true) int rotation,
|
||||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
@Parameter(description = "Comparison type", schema = @Schema(description = "The comparison type, accepts Greater, Equal, Less than", allowableValues = {
|
||||||
throws IOException, InterruptedException {
|
"Greater", "Equal", "Less" })) String comparator)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
// Load the PDF
|
// Load the PDF
|
||||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
||||||
@@ -145,18 +172,26 @@ public class FilterController {
|
|||||||
// Get the rotation of the first page
|
// Get the rotation of the first page
|
||||||
PDPage firstPage = document.getPage(0);
|
PDPage firstPage = document.getPage(0);
|
||||||
int actualRotation = firstPage.getRotation();
|
int actualRotation = firstPage.getRotation();
|
||||||
|
boolean valid = false;
|
||||||
// Perform the comparison
|
// Perform the comparison
|
||||||
switch (comparator) {
|
switch (comparator) {
|
||||||
case "Greater":
|
case "Greater":
|
||||||
return actualRotation > rotation;
|
valid = actualRotation > rotation;
|
||||||
|
break;
|
||||||
case "Equal":
|
case "Equal":
|
||||||
return actualRotation == rotation;
|
valid = actualRotation == rotation;
|
||||||
|
break;
|
||||||
case "Less":
|
case "Less":
|
||||||
return actualRotation < rotation;
|
valid = actualRotation < rotation;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
return WebResponseUtils.multiPartFileToWebResponse(inputFile);
|
||||||
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.other;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
|
import org.apache.pdfbox.text.TextPosition;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Other", description = "Other APIs")
|
||||||
|
public class AutoRenameController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AutoRenameController.class);
|
||||||
|
|
||||||
|
private static final float TITLE_FONT_SIZE_THRESHOLD = 20.0f;
|
||||||
|
private static final int LINE_LIMIT = 11;
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/auto-rename")
|
||||||
|
@Operation(summary = "Extract header from PDF file", description = "This endpoint accepts a PDF file and attempts to extract its title or header based on heuristics. Input:PDF Output:PDF Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> extractHeader(
|
||||||
|
@RequestPart(value = "fileInput") @Parameter(description = "The input PDF file from which the header is to be extracted.", required = true) MultipartFile file,
|
||||||
|
@RequestParam(required = false, defaultValue = "false") @Parameter(description = "Flag indicating whether to use the first text as a fallback if no suitable title is found. Defaults to false.", required = false) Boolean useFirstTextAsFallback)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
PDDocument document = PDDocument.load(file.getInputStream());
|
||||||
|
PDFTextStripper reader = new PDFTextStripper() {
|
||||||
|
class LineInfo {
|
||||||
|
String text;
|
||||||
|
float fontSize;
|
||||||
|
|
||||||
|
LineInfo(String text, float fontSize) {
|
||||||
|
this.text = text;
|
||||||
|
this.fontSize = fontSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<LineInfo> lineInfos = new ArrayList<>();
|
||||||
|
StringBuilder lineBuilder = new StringBuilder();
|
||||||
|
float lastY = -1;
|
||||||
|
float maxFontSizeInLine = 0.0f;
|
||||||
|
int lineCount = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processTextPosition(TextPosition text) {
|
||||||
|
if (lastY != text.getY() && lineCount < LINE_LIMIT) {
|
||||||
|
processLine();
|
||||||
|
lineBuilder = new StringBuilder(text.getUnicode());
|
||||||
|
maxFontSizeInLine = text.getFontSizeInPt();
|
||||||
|
lastY = text.getY();
|
||||||
|
lineCount++;
|
||||||
|
} else if (lineCount < LINE_LIMIT) {
|
||||||
|
lineBuilder.append(text.getUnicode());
|
||||||
|
if (text.getFontSizeInPt() > maxFontSizeInLine) {
|
||||||
|
maxFontSizeInLine = text.getFontSizeInPt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processLine() {
|
||||||
|
if (lineBuilder.length() > 0 && lineCount < LINE_LIMIT) {
|
||||||
|
lineInfos.add(new LineInfo(lineBuilder.toString(), maxFontSizeInLine));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText(PDDocument doc) throws IOException {
|
||||||
|
this.lineInfos.clear();
|
||||||
|
this.lineBuilder = new StringBuilder();
|
||||||
|
this.lastY = -1;
|
||||||
|
this.maxFontSizeInLine = 0.0f;
|
||||||
|
this.lineCount = 0;
|
||||||
|
super.getText(doc);
|
||||||
|
processLine(); // Process the last line
|
||||||
|
|
||||||
|
// Merge lines with same font size
|
||||||
|
List<LineInfo> mergedLineInfos = new ArrayList<>();
|
||||||
|
for (int i = 0; i < lineInfos.size(); i++) {
|
||||||
|
String mergedText = lineInfos.get(i).text;
|
||||||
|
float fontSize = lineInfos.get(i).fontSize;
|
||||||
|
while (i + 1 < lineInfos.size() && lineInfos.get(i + 1).fontSize == fontSize) {
|
||||||
|
mergedText += " " + lineInfos.get(i + 1).text;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
mergedLineInfos.add(new LineInfo(mergedText, fontSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort lines by font size in descending order and get the first one
|
||||||
|
mergedLineInfos.sort(Comparator.comparing((LineInfo li) -> li.fontSize).reversed());
|
||||||
|
String title = mergedLineInfos.isEmpty() ? null : mergedLineInfos.get(0).text;
|
||||||
|
|
||||||
|
return title != null ? title : (useFirstTextAsFallback ? (mergedLineInfos.isEmpty() ? null : mergedLineInfos.get(mergedLineInfos.size() - 1).text) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
String header = reader.getText(document);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sanitize the header string by removing characters not allowed in a filename.
|
||||||
|
if (header != null && header.length() < 255) {
|
||||||
|
header = header.replaceAll("[/\\\\?%*:|\"<>]", "");
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(document, header + ".pdf");
|
||||||
|
} else {
|
||||||
|
logger.info("File has no good title to be found");
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(document, file.getOriginalFilename());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.other;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.DataBufferByte;
|
||||||
|
import java.awt.image.DataBufferInt;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.google.zxing.BinaryBitmap;
|
||||||
|
import com.google.zxing.LuminanceSource;
|
||||||
|
import com.google.zxing.MultiFormatReader;
|
||||||
|
import com.google.zxing.NotFoundException;
|
||||||
|
import com.google.zxing.PlanarYUVLuminanceSource;
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class AutoSplitPdfController {
|
||||||
|
|
||||||
|
private static final String QR_CONTENT = "https://github.com/Frooodle/Stirling-PDF";
|
||||||
|
|
||||||
|
@PostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
|
||||||
|
@Operation(summary = "Auto split PDF pages into separate documents", description = "This endpoint accepts a PDF file, scans each page for a specific QR code, and splits the document at the QR code boundaries. The output is a zip file containing each separate PDF document. Input:PDF Output:ZIP Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> autoSplitPdf(
|
||||||
|
@RequestParam("fileInput") @Parameter(description = "The input PDF file which needs to be split into separate documents based on QR code boundaries.", required = true) MultipartFile file,
|
||||||
|
@RequestParam(value ="duplexMode",defaultValue = "false") @Parameter(description = "Flag indicating if the duplex mode is active, where the page after the divider also gets removed.", required = false) boolean duplexMode)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
InputStream inputStream = file.getInputStream();
|
||||||
|
PDDocument document = PDDocument.load(inputStream);
|
||||||
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
|
|
||||||
|
List<PDDocument> splitDocuments = new ArrayList<>();
|
||||||
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
||||||
|
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150);
|
||||||
|
String result = decodeQRCode(bim);
|
||||||
|
|
||||||
|
if (QR_CONTENT.equals(result) && page != 0) {
|
||||||
|
splitDocuments.add(new PDDocument());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!splitDocuments.isEmpty() && !QR_CONTENT.equals(result)) {
|
||||||
|
splitDocuments.get(splitDocuments.size() - 1).addPage(document.getPage(page));
|
||||||
|
} else if (page == 0) {
|
||||||
|
PDDocument firstDocument = new PDDocument();
|
||||||
|
firstDocument.addPage(document.getPage(page));
|
||||||
|
splitDocuments.add(firstDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If duplexMode is true and current page is a divider, then skip next page
|
||||||
|
if (duplexMode && QR_CONTENT.equals(result)) {
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove split documents that have no pages
|
||||||
|
splitDocuments.removeIf(pdDocument -> pdDocument.getNumberOfPages() == 0);
|
||||||
|
|
||||||
|
for (PDDocument splitDocument : splitDocuments) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
splitDocument.save(baos);
|
||||||
|
splitDocumentsBoas.add(baos);
|
||||||
|
splitDocument.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.close();
|
||||||
|
|
||||||
|
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
|
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
||||||
|
byte[] data;
|
||||||
|
|
||||||
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
||||||
|
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
||||||
|
String fileName = filename + "_" + (i + 1) + ".pdf";
|
||||||
|
ByteArrayOutputStream baos = splitDocumentsBoas.get(i);
|
||||||
|
byte[] pdf = baos.toByteArray();
|
||||||
|
|
||||||
|
ZipEntry pdfEntry = new ZipEntry(fileName);
|
||||||
|
zipOut.putNextEntry(pdfEntry);
|
||||||
|
zipOut.write(pdf);
|
||||||
|
zipOut.closeEntry();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
data = Files.readAllBytes(zipFile);
|
||||||
|
Files.delete(zipFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String decodeQRCode(BufferedImage bufferedImage) {
|
||||||
|
LuminanceSource source;
|
||||||
|
|
||||||
|
if (bufferedImage.getRaster().getDataBuffer() instanceof DataBufferByte) {
|
||||||
|
byte[] pixels = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
|
||||||
|
source = new PlanarYUVLuminanceSource(pixels, bufferedImage.getWidth(), bufferedImage.getHeight(), 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), false);
|
||||||
|
} else if (bufferedImage.getRaster().getDataBuffer() instanceof DataBufferInt) {
|
||||||
|
int[] pixels = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
|
||||||
|
byte[] newPixels = new byte[pixels.length];
|
||||||
|
for (int i = 0; i < pixels.length; i++) {
|
||||||
|
newPixels[i] = (byte) (pixels[i] & 0xff);
|
||||||
|
}
|
||||||
|
source = new PlanarYUVLuminanceSource(newPixels, bufferedImage.getWidth(), bufferedImage.getHeight(), 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), false);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("BufferedImage must have 8-bit gray scale, 24-bit RGB, 32-bit ARGB (packed int), byte gray, or 3-byte/4-byte RGB image data");
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||||
|
|
||||||
|
try {
|
||||||
|
Result result = new MultiFormatReader().decode(bitmap);
|
||||||
|
return result.getText();
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
return null; // there is no QR code in the image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import io.swagger.v3.oas.annotations.Parameter;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -86,10 +87,10 @@ public class BlankPageController {
|
|||||||
List<String> command = new ArrayList<>(Arrays.asList("python3", System.getProperty("user.dir") + "/scripts/detect-blank-pages.py", tempFile.toString() ,"--threshold", String.valueOf(threshold), "--white_percent", String.valueOf(whitePercent)));
|
List<String> command = new ArrayList<>(Arrays.asList("python3", System.getProperty("user.dir") + "/scripts/detect-blank-pages.py", tempFile.toString() ,"--threshold", String.valueOf(threshold), "--white_percent", String.valueOf(whitePercent)));
|
||||||
|
|
||||||
// Run CLI command
|
// Run CLI command
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command);
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// does contain data
|
// does contain data
|
||||||
if (returnCode == 0) {
|
if (returnCode.getRc() == 0) {
|
||||||
System.out.println("page " + pageIndex + " has image which is not blank");
|
System.out.println("page " + pageIndex + " has image which is not blank");
|
||||||
pagesToKeepIndex.add(pageIndex);
|
pagesToKeepIndex.add(pageIndex);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -116,7 +117,7 @@ public class CompressController {
|
|||||||
command.add("-sOutputFile=" + tempOutputFile.toString());
|
command.add("-sOutputFile=" + tempOutputFile.toString());
|
||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
|
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command);
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Check if file size is within expected size or not auto mode so instantly finish
|
// Check if file size is within expected size or not auto mode so instantly finish
|
||||||
long outputFileSize = Files.size(tempOutputFile);
|
long outputFileSize = Files.size(tempOutputFile);
|
||||||
@@ -221,6 +222,15 @@ public class CompressController {
|
|||||||
// Read the optimized PDF file
|
// Read the optimized PDF file
|
||||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
|
||||||
|
// Check if optimized file is larger than the original
|
||||||
|
if(pdfBytes.length > inputFileSize) {
|
||||||
|
// Log the occurrence
|
||||||
|
logger.warn("Optimized file is larger than the original. Returning the original file instead.");
|
||||||
|
|
||||||
|
// Read the original file again
|
||||||
|
pdfBytes = Files.readAllBytes(tempInputFile);
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up the temporary files
|
// Clean up the temporary files
|
||||||
Files.delete(tempInputFile);
|
Files.delete(tempInputFile);
|
||||||
Files.delete(tempOutputFile);
|
Files.delete(tempOutputFile);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -117,7 +118,7 @@ public class ExtractImageScansController {
|
|||||||
|
|
||||||
|
|
||||||
// Run CLI command
|
// Run CLI command
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command);
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the output photos in temp directory
|
// Read the output photos in temp directory
|
||||||
List<Path> tempOutputFiles = Files.list(tempDir).sorted().collect(Collectors.toList());
|
List<Path> tempOutputFiles = Files.list(tempDir).sorted().collect(Collectors.toList());
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import io.swagger.v3.oas.annotations.Parameter;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -141,8 +142,12 @@ public class OCRController {
|
|||||||
command.addAll(Arrays.asList("--language", languageOption, tempInputFile.toString(), tempOutputFile.toString()));
|
command.addAll(Arrays.asList("--language", languageOption, tempInputFile.toString(), tempOutputFile.toString()));
|
||||||
|
|
||||||
// Run CLI command
|
// Run CLI command
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
ProcessExecutorResult result = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
||||||
|
if(result.getRc() != 0 && result.getMessages().contains("multiprocessing/synchronize.py") && result.getMessages().contains("OSError: [Errno 38] Function not implemented")) {
|
||||||
|
command.add("--jobs");
|
||||||
|
command.add("1");
|
||||||
|
result = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +158,7 @@ public class OCRController {
|
|||||||
|
|
||||||
List<String> gsCommand = Arrays.asList("gs", "-sDEVICE=pdfwrite", "-dFILTERIMAGE", "-o", tempPdfWithoutImages.toString(), tempOutputFile.toString());
|
List<String> gsCommand = Arrays.asList("gs", "-sDEVICE=pdfwrite", "-dFILTERIMAGE", "-o", tempPdfWithoutImages.toString(), tempOutputFile.toString());
|
||||||
|
|
||||||
int gsReturnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(gsCommand);
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(gsCommand);
|
||||||
tempOutputFile = tempPdfWithoutImages;
|
tempOutputFile = tempPdfWithoutImages;
|
||||||
}
|
}
|
||||||
// Read the OCR processed PDF file
|
// Read the OCR processed PDF file
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.other;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.itextpdf.io.font.constants.StandardFonts;
|
||||||
|
import com.itextpdf.kernel.font.PdfFont;
|
||||||
|
import com.itextpdf.kernel.font.PdfFontFactory;
|
||||||
|
import com.itextpdf.kernel.geom.Rectangle;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfPage;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfReader;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||||
|
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
|
||||||
|
import com.itextpdf.layout.Canvas;
|
||||||
|
import com.itextpdf.layout.element.Paragraph;
|
||||||
|
import com.itextpdf.layout.properties.TextAlignment;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Other", description = "Other APIs")
|
||||||
|
public class PageNumbersController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PageNumbersController.class);
|
||||||
|
|
||||||
|
@PostMapping(value = "/add-page-numbers", consumes = "multipart/form-data")
|
||||||
|
@Operation(summary = "Add page numbers to a PDF document", description = "This operation takes an input PDF file and adds page numbers to it. Input:PDF Output:PDF Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> addPageNumbers(
|
||||||
|
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
||||||
|
@Parameter(description = "Custom margin: small/medium/large", required = true, schema = @Schema(type = "string", allowableValues = {"small", "medium", "large"})) @RequestParam("customMargin") String customMargin,
|
||||||
|
@Parameter(description = "Position: 1 of 9 positions", required = true, schema = @Schema(type = "integer", minimum = "1", maximum = "9")) @RequestParam("position") int position,
|
||||||
|
@Parameter(description = "Starting number", required = true, schema = @Schema(type = "integer", minimum = "1")) @RequestParam("startingNumber") int startingNumber,
|
||||||
|
@Parameter(description = "Which pages to number, default all", required = false, schema = @Schema(type = "string")) @RequestParam(value = "pagesToNumber", required = false) String pagesToNumber,
|
||||||
|
@Parameter(description = "Custom text: defaults to just number but can have things like \"Page {n} of {p}\"", required = false, schema = @Schema(type = "string")) @RequestParam(value = "customText", required = false) String customText)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
byte[] fileBytes = file.getBytes();
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
|
||||||
|
|
||||||
|
int pageNumber = startingNumber;
|
||||||
|
float marginFactor;
|
||||||
|
switch (customMargin.toLowerCase()) {
|
||||||
|
case "small":
|
||||||
|
marginFactor = 0.02f;
|
||||||
|
break;
|
||||||
|
case "medium":
|
||||||
|
marginFactor = 0.035f;
|
||||||
|
break;
|
||||||
|
case "large":
|
||||||
|
marginFactor = 0.05f;
|
||||||
|
break;
|
||||||
|
case "x-large":
|
||||||
|
marginFactor = 0.1f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
marginFactor = 0.035f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fontSize = 12.0f;
|
||||||
|
|
||||||
|
PdfReader reader = new PdfReader(bais);
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
PdfWriter writer = new PdfWriter(baos);
|
||||||
|
|
||||||
|
PdfDocument pdfDoc = new PdfDocument(reader, writer);
|
||||||
|
|
||||||
|
List<Integer> pagesToNumberList = GeneralUtils.parsePageList(pagesToNumber.split(","), pdfDoc.getNumberOfPages());
|
||||||
|
|
||||||
|
for (int i : pagesToNumberList) {
|
||||||
|
PdfPage page = pdfDoc.getPage(i+1);
|
||||||
|
Rectangle pageSize = page.getPageSize();
|
||||||
|
PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), pdfDoc);
|
||||||
|
|
||||||
|
String text = customText != null ? customText.replace("{n}", String.valueOf(pageNumber)).replace("{total}", String.valueOf(pdfDoc.getNumberOfPages())).replace("{filename}", file.getOriginalFilename().replaceFirst("[.][^.]+$", "")) : String.valueOf(pageNumber);
|
||||||
|
|
||||||
|
PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA);
|
||||||
|
float textWidth = font.getWidth(text, fontSize);
|
||||||
|
float textHeight = font.getAscent(text, fontSize) - font.getDescent(text, fontSize);
|
||||||
|
|
||||||
|
float x, y;
|
||||||
|
TextAlignment alignment;
|
||||||
|
|
||||||
|
int xGroup = (position - 1) % 3;
|
||||||
|
int yGroup = 2 - (position - 1) / 3;
|
||||||
|
|
||||||
|
switch (xGroup) {
|
||||||
|
case 0: // left
|
||||||
|
x = pageSize.getLeft() + marginFactor * pageSize.getWidth();
|
||||||
|
alignment = TextAlignment.LEFT;
|
||||||
|
break;
|
||||||
|
case 1: // center
|
||||||
|
x = pageSize.getLeft() + (pageSize.getWidth()) / 2;
|
||||||
|
alignment = TextAlignment.CENTER;
|
||||||
|
break;
|
||||||
|
default: // right
|
||||||
|
x = pageSize.getRight() - marginFactor * pageSize.getWidth();
|
||||||
|
alignment = TextAlignment.RIGHT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (yGroup) {
|
||||||
|
case 0: // bottom
|
||||||
|
y = pageSize.getBottom() + marginFactor * pageSize.getHeight();
|
||||||
|
break;
|
||||||
|
case 1: // middle
|
||||||
|
y = pageSize.getBottom() + (pageSize.getHeight() ) / 2;
|
||||||
|
break;
|
||||||
|
default: // top
|
||||||
|
y = pageSize.getTop() - marginFactor * pageSize.getHeight();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
new Canvas(pdfCanvas, page.getPageSize())
|
||||||
|
.showTextAligned(new Paragraph(text).setFont(font).setFontSize(fontSize), x, y, alignment);
|
||||||
|
|
||||||
|
pageNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pdfDoc.close();
|
||||||
|
byte[] resultBytes = baos.toByteArray();
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(resultBytes, URLEncoder.encode(file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_numbersAdded.pdf", "UTF-8"), MediaType.APPLICATION_PDF);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -51,7 +52,7 @@ public class RepairController {
|
|||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
|
|
||||||
|
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command);
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Read the optimized PDF file
|
// Read the optimized PDF file
|
||||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.other;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.itextpdf.kernel.pdf.PdfArray;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDictionary;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfName;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfObject;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfReader;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfStream;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Other", description = "Other APIs")
|
||||||
|
public class ShowJavascript {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ShowJavascript.class);
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/show-javascript")
|
||||||
|
@Operation(summary = "Extract header from PDF file", description = "This endpoint accepts a PDF file and attempts to extract its title or header based on heuristics. Input:PDF Output:PDF Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> extractHeader(
|
||||||
|
@RequestPart(value = "fileInput") @Parameter(description = "The input PDF file from which the javascript is to be extracted.", required = true) MultipartFile inputFile)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
try (
|
||||||
|
PdfDocument itextDoc = new PdfDocument(new PdfReader(inputFile.getInputStream()))
|
||||||
|
) {
|
||||||
|
|
||||||
|
String name = "";
|
||||||
|
String script = "";
|
||||||
|
String entryName = "File: "+inputFile.getOriginalFilename() + ", Script: ";
|
||||||
|
//Javascript
|
||||||
|
PdfDictionary namesDict = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names);
|
||||||
|
if (namesDict != null) {
|
||||||
|
PdfDictionary javascriptDict = namesDict.getAsDictionary(PdfName.JavaScript);
|
||||||
|
if (javascriptDict != null) {
|
||||||
|
|
||||||
|
PdfArray namesArray = javascriptDict.getAsArray(PdfName.Names);
|
||||||
|
for (int i = 0; i < namesArray.size(); i += 2) {
|
||||||
|
if(namesArray.getAsString(i) != null)
|
||||||
|
name = namesArray.getAsString(i).toString();
|
||||||
|
|
||||||
|
PdfObject jsCode = namesArray.get(i+1);
|
||||||
|
if (jsCode instanceof PdfStream) {
|
||||||
|
byte[] jsCodeBytes = ((PdfStream)jsCode).getBytes();
|
||||||
|
String jsCodeStr = new String(jsCodeBytes, StandardCharsets.UTF_8);
|
||||||
|
script = "//" + entryName + name + "\n" +jsCodeStr;
|
||||||
|
|
||||||
|
} else if (jsCode instanceof PdfDictionary) {
|
||||||
|
// If the JS code is in a dictionary, you'll need to know the key to use.
|
||||||
|
// Assuming the key is PdfName.JS:
|
||||||
|
PdfStream jsCodeStream = ((PdfDictionary)jsCode).getAsStream(PdfName.JS);
|
||||||
|
if (jsCodeStream != null) {
|
||||||
|
byte[] jsCodeBytes = jsCodeStream.getBytes();
|
||||||
|
String jsCodeStr = new String(jsCodeBytes, StandardCharsets.UTF_8);
|
||||||
|
script = "//" + entryName + name + "\n" +jsCodeStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(script.equals("")) {
|
||||||
|
script = "PDF '" +inputFile.getOriginalFilename() + "' does not contain Javascript";
|
||||||
|
}
|
||||||
|
return WebResponseUtils.bytesToWebResponse(script.getBytes(), name + ".js");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,399 +0,0 @@
|
|||||||
package stirling.software.SPDF.controller.api.pipeline;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
import java.util.zip.ZipOutputStream;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.core.io.ByteArrayResource;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RequestPart;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import stirling.software.SPDF.model.PipelineConfig;
|
|
||||||
import stirling.software.SPDF.model.PipelineOperation;
|
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
|
||||||
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@Tag(name = "Pipeline", description = "Pipeline APIs")
|
|
||||||
public class Controller {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
|
|
||||||
final String jsonFileName = "pipelineCofig.json";
|
|
||||||
final String watchedFoldersDir = "watchedFolders/";
|
|
||||||
@Scheduled(fixedRate = 5000)
|
|
||||||
public void scanFolders() {
|
|
||||||
Path watchedFolderPath = Paths.get(watchedFoldersDir);
|
|
||||||
if (!Files.exists(watchedFolderPath)) {
|
|
||||||
try {
|
|
||||||
Files.createDirectories(watchedFolderPath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try (Stream<Path> paths = Files.walk(watchedFolderPath)) {
|
|
||||||
paths.filter(Files::isDirectory).forEach(t -> {
|
|
||||||
try {
|
|
||||||
if (!t.equals(watchedFolderPath) && !t.endsWith("processing")) {
|
|
||||||
handleDirectory(t);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleDirectory(Path dir) throws Exception {
|
|
||||||
Path jsonFile = dir.resolve(jsonFileName);
|
|
||||||
Path processingDir = dir.resolve("processing"); // Directory to move files during processing
|
|
||||||
if (!Files.exists(processingDir)) {
|
|
||||||
Files.createDirectory(processingDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Files.exists(jsonFile)) {
|
|
||||||
// Read JSON file
|
|
||||||
String jsonString;
|
|
||||||
try {
|
|
||||||
jsonString = new String(Files.readAllBytes(jsonFile));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode JSON to PipelineConfig
|
|
||||||
PipelineConfig config;
|
|
||||||
try {
|
|
||||||
config = objectMapper.readValue(jsonString, PipelineConfig.class);
|
|
||||||
// Assuming your PipelineConfig class has getters for all necessary fields, you can perform checks here
|
|
||||||
if (config.getOperations() == null || config.getOutputDir() == null || config.getName() == null) {
|
|
||||||
throw new IOException("Invalid JSON format");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each operation in the pipeline
|
|
||||||
for (PipelineOperation operation : config.getOperations()) {
|
|
||||||
// Collect all files based on fileInput
|
|
||||||
File[] files;
|
|
||||||
String fileInput = (String) operation.getParameters().get("fileInput");
|
|
||||||
if ("automated".equals(fileInput)) {
|
|
||||||
// If fileInput is "automated", process all files in the directory
|
|
||||||
try (Stream<Path> paths = Files.list(dir)) {
|
|
||||||
files = paths.filter(path -> !path.equals(jsonFile))
|
|
||||||
.map(Path::toFile)
|
|
||||||
.toArray(File[]::new);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If fileInput contains a path, process only this file
|
|
||||||
files = new File[]{new File(fileInput)};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare the files for processing
|
|
||||||
File[] filesToProcess = files.clone();
|
|
||||||
for (File file : filesToProcess) {
|
|
||||||
Files.move(file.toPath(), processingDir.resolve(file.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the files
|
|
||||||
try {
|
|
||||||
List<Resource> resources = handleFiles(filesToProcess, jsonString);
|
|
||||||
|
|
||||||
// Move resultant files and rename them as per config in JSON file
|
|
||||||
for (Resource resource : resources) {
|
|
||||||
String outputFileName = config.getOutputPattern().replace("{filename}", resource.getFile().getName());
|
|
||||||
outputFileName = outputFileName.replace("{pipelineName}", config.getName());
|
|
||||||
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
||||||
outputFileName = outputFileName.replace("{date}", LocalDate.now().format(dateFormatter));
|
|
||||||
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HHmmss");
|
|
||||||
outputFileName = outputFileName.replace("{time}", LocalTime.now().format(timeFormatter));
|
|
||||||
// {filename} {folder} {date} {tmime} {pipeline}
|
|
||||||
|
|
||||||
Files.move(resource.getFile().toPath(), Paths.get(config.getOutputDir(), outputFileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If successful, delete the original files
|
|
||||||
for (File file : filesToProcess) {
|
|
||||||
Files.deleteIfExists(processingDir.resolve(file.getName()));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// If an error occurs, move the original files back
|
|
||||||
for (File file : filesToProcess) {
|
|
||||||
Files.move(processingDir.resolve(file.getName()), file.toPath());
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Resource> processFiles(List<Resource> outputFiles, String jsonString) throws Exception{
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
JsonNode jsonNode = mapper.readTree(jsonString);
|
|
||||||
|
|
||||||
JsonNode pipelineNode = jsonNode.get("pipeline");
|
|
||||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
|
||||||
PrintStream logPrintStream = new PrintStream(logStream);
|
|
||||||
|
|
||||||
boolean hasErrors = false;
|
|
||||||
|
|
||||||
for (JsonNode operationNode : pipelineNode) {
|
|
||||||
String operation = operationNode.get("operation").asText();
|
|
||||||
JsonNode parametersNode = operationNode.get("parameters");
|
|
||||||
String inputFileExtension = "";
|
|
||||||
if(operationNode.has("inputFileType")) {
|
|
||||||
inputFileExtension = operationNode.get("inputFileType").asText();
|
|
||||||
} else {
|
|
||||||
inputFileExtension=".pdf";
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Resource> newOutputFiles = new ArrayList<>();
|
|
||||||
boolean hasInputFileType = false;
|
|
||||||
|
|
||||||
for (Resource file : outputFiles) {
|
|
||||||
if (file.getFilename().endsWith(inputFileExtension)) {
|
|
||||||
hasInputFileType = true;
|
|
||||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
|
||||||
body.add("fileInput", file);
|
|
||||||
|
|
||||||
Iterator<Map.Entry<String, JsonNode>> parameters = parametersNode.fields();
|
|
||||||
while (parameters.hasNext()) {
|
|
||||||
Map.Entry<String, JsonNode> parameter = parameters.next();
|
|
||||||
body.add(parameter.getKey(), parameter.getValue().asText());
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
|
||||||
|
|
||||||
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
|
|
||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
|
||||||
String url = "http://localhost:8080/" + operation;
|
|
||||||
|
|
||||||
ResponseEntity<byte[]> response = restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
|
||||||
|
|
||||||
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
|
||||||
logPrintStream.println("Error: " + response.getBody());
|
|
||||||
hasErrors = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the response body is a zip file
|
|
||||||
if (isZip(response.getBody())) {
|
|
||||||
// Unzip the file and add all the files to the new output files
|
|
||||||
newOutputFiles.addAll(unzip(response.getBody()));
|
|
||||||
} else {
|
|
||||||
Resource outputResource = new ByteArrayResource(response.getBody()) {
|
|
||||||
@Override
|
|
||||||
public String getFilename() {
|
|
||||||
return file.getFilename(); // Preserving original filename
|
|
||||||
}
|
|
||||||
};
|
|
||||||
newOutputFiles.add(outputResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasInputFileType) {
|
|
||||||
logPrintStream.println("No files with extension " + inputFileExtension + " found for operation " + operation);
|
|
||||||
hasErrors = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputFiles = newOutputFiles;
|
|
||||||
}
|
|
||||||
logPrintStream.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
return outputFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
List<Resource> handleFiles(File[] files, String jsonString) throws Exception{
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
JsonNode jsonNode = mapper.readTree(jsonString);
|
|
||||||
|
|
||||||
JsonNode pipelineNode = jsonNode.get("pipeline");
|
|
||||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
|
||||||
PrintStream logPrintStream = new PrintStream(logStream);
|
|
||||||
|
|
||||||
boolean hasErrors = false;
|
|
||||||
List<Resource> outputFiles = new ArrayList<>();
|
|
||||||
|
|
||||||
for (File file : files) {
|
|
||||||
Path path = Paths.get(file.getAbsolutePath());
|
|
||||||
Resource fileResource = new ByteArrayResource(Files.readAllBytes(path)) {
|
|
||||||
@Override
|
|
||||||
public String getFilename() {
|
|
||||||
return file.getName();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
outputFiles.add(fileResource);
|
|
||||||
}
|
|
||||||
return processFiles(outputFiles, jsonString);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Resource> handleFiles(MultipartFile[] files, String jsonString) throws Exception{
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
JsonNode jsonNode = mapper.readTree(jsonString);
|
|
||||||
|
|
||||||
JsonNode pipelineNode = jsonNode.get("pipeline");
|
|
||||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
|
||||||
PrintStream logPrintStream = new PrintStream(logStream);
|
|
||||||
|
|
||||||
boolean hasErrors = false;
|
|
||||||
List<Resource> outputFiles = new ArrayList<>();
|
|
||||||
|
|
||||||
for (MultipartFile file : files) {
|
|
||||||
Resource fileResource = new ByteArrayResource(file.getBytes()) {
|
|
||||||
@Override
|
|
||||||
public String getFilename() {
|
|
||||||
return file.getOriginalFilename();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
outputFiles.add(fileResource);
|
|
||||||
}
|
|
||||||
return processFiles(outputFiles, jsonString);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/handleData")
|
|
||||||
public ResponseEntity<byte[]> handleData(@RequestPart("fileInput") MultipartFile[] files,
|
|
||||||
@RequestParam("json") String jsonString) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
List<Resource> outputFiles = handleFiles(files, jsonString);
|
|
||||||
|
|
||||||
if (outputFiles.size() == 1) {
|
|
||||||
// If there is only one file, return it directly
|
|
||||||
Resource singleFile = outputFiles.get(0);
|
|
||||||
InputStream is = singleFile.getInputStream();
|
|
||||||
byte[] bytes = new byte[(int)singleFile.contentLength()];
|
|
||||||
is.read(bytes);
|
|
||||||
is.close();
|
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(bytes, singleFile.getFilename(), MediaType.APPLICATION_OCTET_STREAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a ByteArrayOutputStream to hold the zip
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
ZipOutputStream zipOut = new ZipOutputStream(baos);
|
|
||||||
|
|
||||||
// Loop through each file and add it to the zip
|
|
||||||
for (Resource file : outputFiles) {
|
|
||||||
ZipEntry zipEntry = new ZipEntry(file.getFilename());
|
|
||||||
zipOut.putNextEntry(zipEntry);
|
|
||||||
|
|
||||||
// Read the file into a byte array
|
|
||||||
InputStream is = file.getInputStream();
|
|
||||||
byte[] bytes = new byte[(int)file.contentLength()];
|
|
||||||
is.read(bytes);
|
|
||||||
|
|
||||||
// Write the bytes of the file to the zip
|
|
||||||
zipOut.write(bytes, 0, bytes.length);
|
|
||||||
zipOut.closeEntry();
|
|
||||||
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
zipOut.close();
|
|
||||||
|
|
||||||
return WebResponseUtils.boasToWebResponse(baos, "output.zip", MediaType.APPLICATION_OCTET_STREAM);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isZip(byte[] data) {
|
|
||||||
if (data == null || data.length < 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the first four bytes of the data against the standard zip magic number
|
|
||||||
return data[0] == 0x50 && data[1] == 0x4B && data[2] == 0x03 && data[3] == 0x04;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Resource> unzip(byte[] data) throws IOException {
|
|
||||||
List<Resource> unzippedFiles = new ArrayList<>();
|
|
||||||
|
|
||||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
|
||||||
ZipInputStream zis = new ZipInputStream(bais)) {
|
|
||||||
|
|
||||||
ZipEntry entry;
|
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int count;
|
|
||||||
|
|
||||||
while ((count = zis.read(buffer)) != -1) {
|
|
||||||
baos.write(buffer, 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String filename = entry.getName();
|
|
||||||
Resource fileResource = new ByteArrayResource(baos.toByteArray()) {
|
|
||||||
@Override
|
|
||||||
public String getFilename() {
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the unzipped file is a zip file, unzip it
|
|
||||||
if (isZip(baos.toByteArray())) {
|
|
||||||
unzippedFiles.addAll(unzip(baos.toByteArray()));
|
|
||||||
} else {
|
|
||||||
unzippedFiles.add(fileResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return unzippedFiles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,521 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.pipeline;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.PipelineConfig;
|
||||||
|
import stirling.software.SPDF.model.PipelineOperation;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Pipeline", description = "Pipeline APIs")
|
||||||
|
public class PipelineController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PipelineController.class);
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
final String jsonFileName = "pipelineConfig.json";
|
||||||
|
final String watchedFoldersDir = "./pipeline/watchedFolders/";
|
||||||
|
final String finishedFoldersDir = "./pipeline/finishedFolders/";
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 25000)
|
||||||
|
public void scanFolders() {
|
||||||
|
logger.info("Scanning folders...");
|
||||||
|
Path watchedFolderPath = Paths.get(watchedFoldersDir);
|
||||||
|
if (!Files.exists(watchedFolderPath)) {
|
||||||
|
try {
|
||||||
|
Files.createDirectories(watchedFolderPath);
|
||||||
|
logger.info("Created directory: {}", watchedFolderPath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error creating directory: {}", watchedFolderPath, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try (Stream<Path> paths = Files.walk(watchedFolderPath)) {
|
||||||
|
paths.filter(Files::isDirectory).forEach(t -> {
|
||||||
|
try {
|
||||||
|
if (!t.equals(watchedFolderPath) && !t.endsWith("processing")) {
|
||||||
|
handleDirectory(t);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error handling directory: {}", t, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error walking through directory: {}", watchedFolderPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
|
||||||
|
private void handleDirectory(Path dir) throws Exception {
|
||||||
|
logger.info("Handling directory: {}", dir);
|
||||||
|
Path jsonFile = dir.resolve(jsonFileName);
|
||||||
|
Path processingDir = dir.resolve("processing"); // Directory to move files during processing
|
||||||
|
if (!Files.exists(processingDir)) {
|
||||||
|
Files.createDirectory(processingDir);
|
||||||
|
logger.info("Created processing directory: {}", processingDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Files.exists(jsonFile)) {
|
||||||
|
// Read JSON file
|
||||||
|
String jsonString;
|
||||||
|
try {
|
||||||
|
jsonString = new String(Files.readAllBytes(jsonFile));
|
||||||
|
logger.info("Read JSON file: {}", jsonFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error reading JSON file: {}", jsonFile, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode JSON to PipelineConfig
|
||||||
|
PipelineConfig config;
|
||||||
|
try {
|
||||||
|
config = objectMapper.readValue(jsonString, PipelineConfig.class);
|
||||||
|
// Assuming your PipelineConfig class has getters for all necessary fields, you
|
||||||
|
// can perform checks here
|
||||||
|
if (config.getOperations() == null || config.getOutputDir() == null || config.getName() == null) {
|
||||||
|
throw new IOException("Invalid JSON format");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error parsing PipelineConfig: {}", jsonString, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each operation in the pipeline
|
||||||
|
for (PipelineOperation operation : config.getOperations()) {
|
||||||
|
// Collect all files based on fileInput
|
||||||
|
File[] files;
|
||||||
|
String fileInput = (String) operation.getParameters().get("fileInput");
|
||||||
|
if ("automated".equals(fileInput)) {
|
||||||
|
// If fileInput is "automated", process all files in the directory
|
||||||
|
try (Stream<Path> paths = Files.list(dir)) {
|
||||||
|
files = paths
|
||||||
|
.filter(path -> !Files.isDirectory(path)) // exclude directories
|
||||||
|
.filter(path -> !path.equals(jsonFile)) // exclude jsonFile
|
||||||
|
.map(Path::toFile)
|
||||||
|
.toArray(File[]::new);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If fileInput contains a path, process only this file
|
||||||
|
files = new File[] { new File(fileInput) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the files for processing
|
||||||
|
List<File> filesToProcess = new ArrayList<>();
|
||||||
|
for (File file : files) {
|
||||||
|
logger.info(file.getName());
|
||||||
|
logger.info("{} to {}",file.toPath(), processingDir.resolve(file.getName()));
|
||||||
|
Files.move(file.toPath(), processingDir.resolve(file.getName()));
|
||||||
|
filesToProcess.add(processingDir.resolve(file.getName()).toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the files
|
||||||
|
try {
|
||||||
|
List<Resource> resources = handleFiles(filesToProcess.toArray(new File[0]), jsonString);
|
||||||
|
|
||||||
|
if(resources == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Move resultant files and rename them as per config in JSON file
|
||||||
|
for (Resource resource : resources) {
|
||||||
|
String resourceName = resource.getFilename();
|
||||||
|
String baseName = resourceName.substring(0, resourceName.lastIndexOf("."));
|
||||||
|
String extension = resourceName.substring(resourceName.lastIndexOf(".")+1);
|
||||||
|
|
||||||
|
String outputFileName = config.getOutputPattern().replace("{filename}", baseName);
|
||||||
|
|
||||||
|
outputFileName = outputFileName.replace("{pipelineName}", config.getName());
|
||||||
|
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||||
|
outputFileName = outputFileName.replace("{date}", LocalDate.now().format(dateFormatter));
|
||||||
|
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HHmmss");
|
||||||
|
outputFileName = outputFileName.replace("{time}", LocalTime.now().format(timeFormatter));
|
||||||
|
|
||||||
|
outputFileName += "." + extension;
|
||||||
|
// {filename} {folder} {date} {tmime} {pipeline}
|
||||||
|
String outputDir = config.getOutputDir();
|
||||||
|
|
||||||
|
String outputFolder = applicationProperties.getAutoPipeline().getOutputFolder();
|
||||||
|
|
||||||
|
if (outputFolder == null || outputFolder.isEmpty()) {
|
||||||
|
// If the environment variable is not set, use the default value
|
||||||
|
outputFolder = finishedFoldersDir;
|
||||||
|
}
|
||||||
|
logger.info("outputDir 0={}", outputDir);
|
||||||
|
// Replace the placeholders in the outputDir string
|
||||||
|
outputDir = outputDir.replace("{outputFolder}", outputFolder);
|
||||||
|
outputDir = outputDir.replace("{folderName}", dir.toString());
|
||||||
|
logger.info("outputDir 1={}", outputDir);
|
||||||
|
outputDir = outputDir.replace("\\watchedFolders", "");
|
||||||
|
outputDir = outputDir.replace("//watchedFolders", "");
|
||||||
|
outputDir = outputDir.replace("\\\\watchedFolders", "");
|
||||||
|
outputDir = outputDir.replace("/watchedFolders", "");
|
||||||
|
|
||||||
|
Path outputPath;
|
||||||
|
logger.info("outputDir 2={}", outputDir);
|
||||||
|
if (Paths.get(outputDir).isAbsolute()) {
|
||||||
|
// If it's an absolute path, use it directly
|
||||||
|
outputPath = Paths.get(outputDir);
|
||||||
|
} else {
|
||||||
|
// If it's a relative path, make it relative to the current working directory
|
||||||
|
outputPath = Paths.get(".", outputDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("outputPath={}", outputPath);
|
||||||
|
|
||||||
|
if (!Files.exists(outputPath)) {
|
||||||
|
try {
|
||||||
|
Files.createDirectories(outputPath);
|
||||||
|
logger.info("Created directory: {}", outputPath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error creating directory: {}", outputPath, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("outputPath {}", outputPath);
|
||||||
|
logger.info("outputPath.resolve(outputFileName).toString() {}", outputPath.resolve(outputFileName).toString());
|
||||||
|
File newFile = new File(outputPath.resolve(outputFileName).toString());
|
||||||
|
OutputStream os = new FileOutputStream(newFile);
|
||||||
|
os.write(((ByteArrayResource)resource).getByteArray());
|
||||||
|
os.close();
|
||||||
|
logger.info("made {}", outputPath.resolve(outputFileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If successful, delete the original files
|
||||||
|
for (File file : filesToProcess) {
|
||||||
|
Files.deleteIfExists(processingDir.resolve(file.getName()));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If an error occurs, move the original files back
|
||||||
|
for (File file : filesToProcess) {
|
||||||
|
Files.move(processingDir.resolve(file.getName()), file.toPath());
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Resource> processFiles(List<Resource> outputFiles, String jsonString) throws Exception {
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode jsonNode = mapper.readTree(jsonString);
|
||||||
|
|
||||||
|
JsonNode pipelineNode = jsonNode.get("pipeline");
|
||||||
|
logger.info("Running pipelineNode: {}", pipelineNode);
|
||||||
|
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||||
|
PrintStream logPrintStream = new PrintStream(logStream);
|
||||||
|
|
||||||
|
boolean hasErrors = false;
|
||||||
|
|
||||||
|
for (JsonNode operationNode : pipelineNode) {
|
||||||
|
String operation = operationNode.get("operation").asText();
|
||||||
|
logger.info("Running operation: {}", operation);
|
||||||
|
JsonNode parametersNode = operationNode.get("parameters");
|
||||||
|
String inputFileExtension = "";
|
||||||
|
if (operationNode.has("inputFileType")) {
|
||||||
|
inputFileExtension = operationNode.get("inputFileType").asText();
|
||||||
|
} else {
|
||||||
|
inputFileExtension = ".pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Resource> newOutputFiles = new ArrayList<>();
|
||||||
|
boolean hasInputFileType = false;
|
||||||
|
|
||||||
|
for (Resource file : outputFiles) {
|
||||||
|
if (file.getFilename().endsWith(inputFileExtension)) {
|
||||||
|
hasInputFileType = true;
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("fileInput", file);
|
||||||
|
|
||||||
|
Iterator<Map.Entry<String, JsonNode>> parameters = parametersNode.fields();
|
||||||
|
while (parameters.hasNext()) {
|
||||||
|
Map.Entry<String, JsonNode> parameter = parameters.next();
|
||||||
|
body.add(parameter.getKey(), parameter.getValue().asText());
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||||
|
|
||||||
|
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
String url = "http://localhost:8080/" + operation;
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> response = restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
||||||
|
|
||||||
|
// If the operation is filter and the response body is null or empty, skip this file
|
||||||
|
if (operation.startsWith("filter-") && (response.getBody() == null || response.getBody().length == 0)) {
|
||||||
|
logger.info("Skipping file due to failing {}", operation);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
logPrintStream.println("Error: " + response.getBody());
|
||||||
|
hasErrors = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Define filename
|
||||||
|
String filename;
|
||||||
|
if ("auto-rename".equals(operation)) {
|
||||||
|
// If the operation is "auto-rename", generate a new filename.
|
||||||
|
// This is a simple example of generating a filename using current timestamp.
|
||||||
|
// Modify as per your needs.
|
||||||
|
filename = "file_" + System.currentTimeMillis();
|
||||||
|
} else {
|
||||||
|
// Otherwise, keep the original filename.
|
||||||
|
filename = file.getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the response body is a zip file
|
||||||
|
if (isZip(response.getBody())) {
|
||||||
|
// Unzip the file and add all the files to the new output files
|
||||||
|
newOutputFiles.addAll(unzip(response.getBody()));
|
||||||
|
} else {
|
||||||
|
Resource outputResource = new ByteArrayResource(response.getBody()) {
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
newOutputFiles.add(outputResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasInputFileType) {
|
||||||
|
logPrintStream.println(
|
||||||
|
"No files with extension " + inputFileExtension + " found for operation " + operation);
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFiles = newOutputFiles;
|
||||||
|
}
|
||||||
|
logPrintStream.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
if (hasErrors) {
|
||||||
|
logger.error("Errors occurred during processing. Log: {}", logStream.toString());
|
||||||
|
}
|
||||||
|
return outputFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Resource> handleFiles(File[] files, String jsonString) throws Exception {
|
||||||
|
if(files == null || files.length == 0) {
|
||||||
|
logger.info("No files");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Handling files: {} files, with JSON string of length: {}", files.length, jsonString.length());
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode jsonNode = mapper.readTree(jsonString);
|
||||||
|
|
||||||
|
JsonNode pipelineNode = jsonNode.get("pipeline");
|
||||||
|
|
||||||
|
boolean hasErrors = false;
|
||||||
|
List<Resource> outputFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
Path path = Paths.get(file.getAbsolutePath());
|
||||||
|
System.out.println("Reading file: " + path); // debug statement
|
||||||
|
|
||||||
|
if (Files.exists(path)) {
|
||||||
|
Resource fileResource = new ByteArrayResource(Files.readAllBytes(path)) {
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
outputFiles.add(fileResource);
|
||||||
|
} else {
|
||||||
|
System.out.println("File not found: " + path); // debug statement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("Files successfully loaded. Starting processing...");
|
||||||
|
return processFiles(outputFiles, jsonString);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Resource> handleFiles(MultipartFile[] files, String jsonString) throws Exception {
|
||||||
|
if(files == null || files.length == 0) {
|
||||||
|
logger.info("No files");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
logger.info("Handling files: {} files, with JSON string of length: {}", files.length, jsonString.length());
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode jsonNode = mapper.readTree(jsonString);
|
||||||
|
|
||||||
|
JsonNode pipelineNode = jsonNode.get("pipeline");
|
||||||
|
|
||||||
|
boolean hasErrors = false;
|
||||||
|
List<Resource> outputFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
for (MultipartFile file : files) {
|
||||||
|
Resource fileResource = new ByteArrayResource(file.getBytes()) {
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return file.getOriginalFilename();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
outputFiles.add(fileResource);
|
||||||
|
}
|
||||||
|
logger.info("Files successfully loaded. Starting processing...");
|
||||||
|
return processFiles(outputFiles, jsonString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/handleData")
|
||||||
|
public ResponseEntity<byte[]> handleData(@RequestPart("fileInput") MultipartFile[] files,
|
||||||
|
@RequestParam("json") String jsonString) {
|
||||||
|
logger.info("Received POST request to /handleData with {} files", files.length);
|
||||||
|
try {
|
||||||
|
List<Resource> outputFiles = handleFiles(files, jsonString);
|
||||||
|
|
||||||
|
if (outputFiles != null && outputFiles.size() == 1) {
|
||||||
|
// If there is only one file, return it directly
|
||||||
|
Resource singleFile = outputFiles.get(0);
|
||||||
|
InputStream is = singleFile.getInputStream();
|
||||||
|
byte[] bytes = new byte[(int) singleFile.contentLength()];
|
||||||
|
is.read(bytes);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
logger.info("Returning single file response...");
|
||||||
|
return WebResponseUtils.bytesToWebResponse(bytes, singleFile.getFilename(),
|
||||||
|
MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
} else if (outputFiles == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a ByteArrayOutputStream to hold the zip
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ZipOutputStream zipOut = new ZipOutputStream(baos);
|
||||||
|
|
||||||
|
// Loop through each file and add it to the zip
|
||||||
|
for (Resource file : outputFiles) {
|
||||||
|
ZipEntry zipEntry = new ZipEntry(file.getFilename());
|
||||||
|
zipOut.putNextEntry(zipEntry);
|
||||||
|
|
||||||
|
// Read the file into a byte array
|
||||||
|
InputStream is = file.getInputStream();
|
||||||
|
byte[] bytes = new byte[(int) file.contentLength()];
|
||||||
|
is.read(bytes);
|
||||||
|
|
||||||
|
// Write the bytes of the file to the zip
|
||||||
|
zipOut.write(bytes, 0, bytes.length);
|
||||||
|
zipOut.closeEntry();
|
||||||
|
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
zipOut.close();
|
||||||
|
|
||||||
|
logger.info("Returning zipped file response...");
|
||||||
|
return WebResponseUtils.boasToWebResponse(baos, "output.zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error handling data: ", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isZip(byte[] data) {
|
||||||
|
if (data == null || data.length < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the first four bytes of the data against the standard zip magic number
|
||||||
|
return data[0] == 0x50 && data[1] == 0x4B && data[2] == 0x03 && data[3] == 0x04;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Resource> unzip(byte[] data) throws IOException {
|
||||||
|
logger.info("Unzipping data of length: {}", data.length);
|
||||||
|
List<Resource> unzippedFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||||
|
ZipInputStream zis = new ZipInputStream(bais)) {
|
||||||
|
|
||||||
|
ZipEntry entry;
|
||||||
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int count;
|
||||||
|
|
||||||
|
while ((count = zis.read(buffer)) != -1) {
|
||||||
|
baos.write(buffer, 0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String filename = entry.getName();
|
||||||
|
Resource fileResource = new ByteArrayResource(baos.toByteArray()) {
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the unzipped file is a zip file, unzip it
|
||||||
|
if (isZip(baos.toByteArray())) {
|
||||||
|
logger.info("File {} is a zip file. Unzipping...", filename);
|
||||||
|
unzippedFiles.addAll(unzip(baos.toByteArray()));
|
||||||
|
} else {
|
||||||
|
unzippedFiles.add(fileResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Unzipping completed. {} files were unzipped.", unzippedFiles.size());
|
||||||
|
return unzippedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,763 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.cos.COSString;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
|
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement;
|
||||||
|
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureNode;
|
||||||
|
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
|
||||||
|
import org.apache.pdfbox.pdmodel.encryption.PDEncryption;
|
||||||
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import com.itextpdf.forms.PdfAcroForm;
|
||||||
|
import com.itextpdf.forms.fields.PdfFormField;
|
||||||
|
import com.itextpdf.kernel.geom.Rectangle;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfArray;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfCatalog;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDictionary;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfName;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfObject;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfOutline;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfReader;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfResources;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfStream;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfString;
|
||||||
|
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
|
||||||
|
import com.itextpdf.kernel.pdf.annot.PdfFileAttachmentAnnotation;
|
||||||
|
import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation;
|
||||||
|
import com.itextpdf.kernel.pdf.layer.PdfLayer;
|
||||||
|
import com.itextpdf.kernel.pdf.layer.PdfOCProperties;
|
||||||
|
import com.itextpdf.kernel.xmp.XMPException;
|
||||||
|
import com.itextpdf.kernel.xmp.XMPMeta;
|
||||||
|
import com.itextpdf.kernel.xmp.XMPMetaFactory;
|
||||||
|
import com.itextpdf.kernel.xmp.options.SerializeOptions;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
|
public class GetInfoOnPDF {
|
||||||
|
|
||||||
|
static ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
|
||||||
|
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> getPdfInfo(
|
||||||
|
@RequestPart(required = true, value = "fileInput")
|
||||||
|
@Parameter(description = "The input PDF file to get info on", required = true) MultipartFile inputFile)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
try (
|
||||||
|
PDDocument pdfBoxDoc = PDDocument.load(inputFile.getInputStream());
|
||||||
|
PdfDocument itextDoc = new PdfDocument(new PdfReader(inputFile.getInputStream()))
|
||||||
|
) {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
ObjectNode jsonOutput = objectMapper.createObjectNode();
|
||||||
|
|
||||||
|
// Metadata using PDFBox
|
||||||
|
PDDocumentInformation info = pdfBoxDoc.getDocumentInformation();
|
||||||
|
ObjectNode metadata = objectMapper.createObjectNode();
|
||||||
|
ObjectNode basicInfo = objectMapper.createObjectNode();
|
||||||
|
ObjectNode docInfoNode = objectMapper.createObjectNode();
|
||||||
|
ObjectNode compliancy = objectMapper.createObjectNode();
|
||||||
|
ObjectNode encryption = objectMapper.createObjectNode();
|
||||||
|
ObjectNode other = objectMapper.createObjectNode();
|
||||||
|
|
||||||
|
|
||||||
|
metadata.put("Title", info.getTitle());
|
||||||
|
metadata.put("Author", info.getAuthor());
|
||||||
|
metadata.put("Subject", info.getSubject());
|
||||||
|
metadata.put("Keywords", info.getKeywords());
|
||||||
|
metadata.put("Producer", info.getProducer());
|
||||||
|
metadata.put("Creator", info.getCreator());
|
||||||
|
metadata.put("CreationDate", formatDate(info.getCreationDate()));
|
||||||
|
metadata.put("ModificationDate", formatDate(info.getModificationDate()));
|
||||||
|
jsonOutput.set("Metadata", metadata);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Total file size of the PDF
|
||||||
|
long fileSizeInBytes = inputFile.getSize();
|
||||||
|
basicInfo.put("FileSizeInBytes", fileSizeInBytes);
|
||||||
|
|
||||||
|
// Number of words, paragraphs, and images in the entire document
|
||||||
|
String fullText = new PDFTextStripper().getText(pdfBoxDoc);
|
||||||
|
String[] words = fullText.split("\\s+");
|
||||||
|
int wordCount = words.length;
|
||||||
|
int paragraphCount = fullText.split("\r\n|\r|\n").length;
|
||||||
|
basicInfo.put("WordCount", wordCount);
|
||||||
|
basicInfo.put("ParagraphCount", paragraphCount);
|
||||||
|
// Number of characters in the entire document (including spaces and special characters)
|
||||||
|
int charCount = fullText.length();
|
||||||
|
basicInfo.put("CharacterCount", charCount);
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize the flags and types
|
||||||
|
boolean hasCompression = false;
|
||||||
|
String compressionType = "None";
|
||||||
|
|
||||||
|
// Check for object streams
|
||||||
|
for (int i = 1; i <= itextDoc.getNumberOfPdfObjects(); i++) {
|
||||||
|
PdfObject obj = itextDoc.getPdfObject(i);
|
||||||
|
if (obj != null && obj.isStream() && ((PdfStream) obj).get(PdfName.Type) == PdfName.ObjStm) {
|
||||||
|
hasCompression = true;
|
||||||
|
compressionType = "Object Streams";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not compressed using object streams, check for compressed Xref tables
|
||||||
|
if (!hasCompression && itextDoc.getReader().hasRebuiltXref()) {
|
||||||
|
hasCompression = true;
|
||||||
|
compressionType = "Compressed Xref or Rebuilt Xref";
|
||||||
|
}
|
||||||
|
basicInfo.put("Compression", hasCompression);
|
||||||
|
if(hasCompression)
|
||||||
|
basicInfo.put("CompressionType", compressionType);
|
||||||
|
|
||||||
|
String language = pdfBoxDoc.getDocumentCatalog().getLanguage();
|
||||||
|
basicInfo.put("Language", language);
|
||||||
|
basicInfo.put("Number of pages", pdfBoxDoc.getNumberOfPages());
|
||||||
|
|
||||||
|
|
||||||
|
// Page Mode using iText7
|
||||||
|
PdfCatalog catalog = itextDoc.getCatalog();
|
||||||
|
PdfName pageMode = catalog.getPdfObject().getAsName(PdfName.PageMode);
|
||||||
|
|
||||||
|
// Document Information using PDFBox
|
||||||
|
docInfoNode.put("PDF version", pdfBoxDoc.getVersion());
|
||||||
|
docInfoNode.put("Trapped", info.getTrapped());
|
||||||
|
docInfoNode.put("Page Mode", getPageModeDescription(pageMode));;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PdfAcroForm acroForm = PdfAcroForm.getAcroForm(itextDoc, false);
|
||||||
|
ObjectNode formFieldsNode = objectMapper.createObjectNode();
|
||||||
|
if (acroForm != null) {
|
||||||
|
for (Map.Entry<String, PdfFormField> entry : acroForm.getFormFields().entrySet()) {
|
||||||
|
formFieldsNode.put(entry.getKey(), entry.getValue().getValueAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsonOutput.set("FormFields", formFieldsNode);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//embeed files TODO size
|
||||||
|
ArrayNode embeddedFilesArray = objectMapper.createArrayNode();
|
||||||
|
if(itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names) != null)
|
||||||
|
{
|
||||||
|
PdfDictionary embeddedFiles = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names)
|
||||||
|
.getAsDictionary(PdfName.EmbeddedFiles);
|
||||||
|
if (embeddedFiles != null) {
|
||||||
|
|
||||||
|
PdfArray namesArray = embeddedFiles.getAsArray(PdfName.Names);
|
||||||
|
if(namesArray != null) {
|
||||||
|
for (int i = 0; i < namesArray.size(); i += 2) {
|
||||||
|
ObjectNode embeddedFileNode = objectMapper.createObjectNode();
|
||||||
|
embeddedFileNode.put("Name", namesArray.getAsString(i).toString());
|
||||||
|
// Add other details if required
|
||||||
|
embeddedFilesArray.add(embeddedFileNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other.set("EmbeddedFiles", embeddedFilesArray);
|
||||||
|
|
||||||
|
//attachments TODO size
|
||||||
|
ArrayNode attachmentsArray = objectMapper.createArrayNode();
|
||||||
|
for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) {
|
||||||
|
for (PdfAnnotation annotation : itextDoc.getPage(pageNum).getAnnotations()) {
|
||||||
|
if (annotation instanceof PdfFileAttachmentAnnotation) {
|
||||||
|
ObjectNode attachmentNode = objectMapper.createObjectNode();
|
||||||
|
attachmentNode.put("Name", ((PdfFileAttachmentAnnotation) annotation).getName().toString());
|
||||||
|
attachmentNode.put("Description", annotation.getContents().getValue());
|
||||||
|
attachmentsArray.add(attachmentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other.set("Attachments", attachmentsArray);
|
||||||
|
|
||||||
|
//Javascript
|
||||||
|
PdfDictionary namesDict = itextDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.Names);
|
||||||
|
ArrayNode javascriptArray = objectMapper.createArrayNode();
|
||||||
|
if (namesDict != null) {
|
||||||
|
PdfDictionary javascriptDict = namesDict.getAsDictionary(PdfName.JavaScript);
|
||||||
|
if (javascriptDict != null) {
|
||||||
|
|
||||||
|
PdfArray namesArray = javascriptDict.getAsArray(PdfName.Names);
|
||||||
|
for (int i = 0; i < namesArray.size(); i += 2) {
|
||||||
|
ObjectNode jsNode = objectMapper.createObjectNode();
|
||||||
|
if(namesArray.getAsString(i) != null)
|
||||||
|
jsNode.put("JS Name", namesArray.getAsString(i).toString());
|
||||||
|
|
||||||
|
// Here we check for a PdfStream object and retrieve the JS code from it
|
||||||
|
PdfObject jsCode = namesArray.get(i+1);
|
||||||
|
if (jsCode instanceof PdfStream) {
|
||||||
|
byte[] jsCodeBytes = ((PdfStream)jsCode).getBytes();
|
||||||
|
String jsCodeStr = new String(jsCodeBytes, StandardCharsets.UTF_8);
|
||||||
|
jsNode.put("JS Script Length", jsCodeStr.length());
|
||||||
|
} else if (jsCode instanceof PdfDictionary) {
|
||||||
|
// If the JS code is in a dictionary, you'll need to know the key to use.
|
||||||
|
// Assuming the key is PdfName.JS:
|
||||||
|
PdfStream jsCodeStream = ((PdfDictionary)jsCode).getAsStream(PdfName.JS);
|
||||||
|
if (jsCodeStream != null) {
|
||||||
|
byte[] jsCodeBytes = jsCodeStream.getBytes();
|
||||||
|
String jsCodeStr = new String(jsCodeBytes, StandardCharsets.UTF_8);
|
||||||
|
jsNode.put("JS Script Character Length", jsCodeStr.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
javascriptArray.add(jsNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other.set("JavaScript", javascriptArray);
|
||||||
|
|
||||||
|
//TODO size
|
||||||
|
PdfOCProperties ocProperties = itextDoc.getCatalog().getOCProperties(false);
|
||||||
|
ArrayNode layersArray = objectMapper.createArrayNode();
|
||||||
|
if (ocProperties != null) {
|
||||||
|
|
||||||
|
for (PdfLayer layer : ocProperties.getLayers()) {
|
||||||
|
ObjectNode layerNode = objectMapper.createObjectNode();
|
||||||
|
layerNode.put("Name", layer.getPdfObject().getAsString(PdfName.Name).toString());
|
||||||
|
layersArray.add(layerNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
other.set("Layers", layersArray);
|
||||||
|
|
||||||
|
//TODO Security
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Digital Signatures using iText7 TODO
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PDStructureTreeRoot structureTreeRoot = pdfBoxDoc.getDocumentCatalog().getStructureTreeRoot();
|
||||||
|
ArrayNode structureTreeArray;
|
||||||
|
try {
|
||||||
|
if(structureTreeRoot != null) {
|
||||||
|
structureTreeArray = exploreStructureTree(structureTreeRoot.getKids());
|
||||||
|
other.set("StructureTree", structureTreeArray);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boolean isPdfACompliant = checkOutputIntent(itextDoc, "PDF/A");
|
||||||
|
boolean isPdfXCompliant = checkOutputIntent(itextDoc, "PDF/X");
|
||||||
|
boolean isPdfECompliant = checkForStandard(itextDoc, "PDF/E");
|
||||||
|
boolean isPdfVTCompliant = checkForStandard(itextDoc, "PDF/VT");
|
||||||
|
boolean isPdfUACompliant = checkForStandard(itextDoc, "PDF/UA");
|
||||||
|
boolean isPdfBCompliant = checkForStandard(itextDoc, "PDF/B"); // If you want to check for PDF/Broadcast, though this isn't an official ISO standard.
|
||||||
|
boolean isPdfSECCompliant = checkForStandard(itextDoc, "PDF/SEC"); // This might not be effective since PDF/SEC was under development in 2021.
|
||||||
|
|
||||||
|
compliancy.put("IsPDF/ACompliant", isPdfACompliant);
|
||||||
|
compliancy.put("IsPDF/XCompliant", isPdfXCompliant);
|
||||||
|
compliancy.put("IsPDF/ECompliant", isPdfECompliant);
|
||||||
|
compliancy.put("IsPDF/VTCompliant", isPdfVTCompliant);
|
||||||
|
compliancy.put("IsPDF/UACompliant", isPdfUACompliant);
|
||||||
|
compliancy.put("IsPDF/BCompliant", isPdfBCompliant);
|
||||||
|
compliancy.put("IsPDF/SECCompliant", isPdfSECCompliant);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ArrayNode bookmarksArray = objectMapper.createArrayNode();
|
||||||
|
PdfOutline root = itextDoc.getOutlines(false);
|
||||||
|
if (root != null) {
|
||||||
|
for (PdfOutline child : root.getAllChildren()) {
|
||||||
|
addOutlinesToArray(child, bookmarksArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other.set("Bookmarks/Outline/TOC", bookmarksArray);
|
||||||
|
|
||||||
|
byte[] xmpBytes = itextDoc.getXmpMetadata();
|
||||||
|
String xmpString = null;
|
||||||
|
if (xmpBytes != null) {
|
||||||
|
try {
|
||||||
|
XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(xmpBytes);
|
||||||
|
xmpString = new String(XMPMetaFactory.serializeToBuffer(xmpMeta, new SerializeOptions()));
|
||||||
|
} catch (XMPException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other.put("XMPMetadata", xmpString);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (pdfBoxDoc.isEncrypted()) {
|
||||||
|
encryption.put("IsEncrypted", true);
|
||||||
|
|
||||||
|
// Retrieve encryption details using getEncryption()
|
||||||
|
PDEncryption pdfEncryption = pdfBoxDoc.getEncryption();
|
||||||
|
encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter());
|
||||||
|
encryption.put("KeyLength", pdfEncryption.getLength());
|
||||||
|
encryption.put("Permissions", pdfBoxDoc.getCurrentAccessPermission().toString());
|
||||||
|
|
||||||
|
// Add other encryption-related properties as needed
|
||||||
|
} else {
|
||||||
|
encryption.put("IsEncrypted", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ObjectNode pageInfoParent = objectMapper.createObjectNode();
|
||||||
|
for (int pageNum = 1; pageNum <= itextDoc.getNumberOfPages(); pageNum++) {
|
||||||
|
ObjectNode pageInfo = objectMapper.createObjectNode();
|
||||||
|
|
||||||
|
// Page-level Information
|
||||||
|
Rectangle pageSize = itextDoc.getPage(pageNum).getPageSize();
|
||||||
|
pageInfo.put("Width", pageSize.getWidth());
|
||||||
|
pageInfo.put("Height", pageSize.getHeight());
|
||||||
|
pageInfo.put("Rotation", itextDoc.getPage(pageNum).getRotation());
|
||||||
|
pageInfo.put("Page Orientation", getPageOrientation(pageSize.getWidth(),pageSize.getHeight()));
|
||||||
|
pageInfo.put("Standard Size", getPageSize(pageSize.getWidth(),pageSize.getHeight()));
|
||||||
|
|
||||||
|
// Boxes
|
||||||
|
pageInfo.put("MediaBox", itextDoc.getPage(pageNum).getMediaBox().toString());
|
||||||
|
pageInfo.put("CropBox", itextDoc.getPage(pageNum).getCropBox().toString());
|
||||||
|
pageInfo.put("BleedBox", itextDoc.getPage(pageNum).getBleedBox().toString());
|
||||||
|
pageInfo.put("TrimBox", itextDoc.getPage(pageNum).getTrimBox().toString());
|
||||||
|
pageInfo.put("ArtBox", itextDoc.getPage(pageNum).getArtBox().toString());
|
||||||
|
|
||||||
|
// Content Extraction
|
||||||
|
PDFTextStripper textStripper = new PDFTextStripper();
|
||||||
|
textStripper.setStartPage(pageNum -1);
|
||||||
|
textStripper.setEndPage(pageNum - 1);
|
||||||
|
String pageText = textStripper.getText(pdfBoxDoc);
|
||||||
|
|
||||||
|
pageInfo.put("Text Characters Count", pageText.length()); //
|
||||||
|
|
||||||
|
// Annotations
|
||||||
|
List<PdfAnnotation> annotations = itextDoc.getPage(pageNum).getAnnotations();
|
||||||
|
|
||||||
|
int subtypeCount = 0;
|
||||||
|
int contentsCount = 0;
|
||||||
|
|
||||||
|
for (PdfAnnotation annotation : annotations) {
|
||||||
|
if(annotation.getSubtype() != null) {
|
||||||
|
subtypeCount++; // Increase subtype count
|
||||||
|
}
|
||||||
|
if(annotation.getContents() != null) {
|
||||||
|
contentsCount++; // Increase contents count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectNode annotationsObject = objectMapper.createObjectNode();
|
||||||
|
annotationsObject.put("AnnotationsCount", annotations.size());
|
||||||
|
annotationsObject.put("SubtypeCount", subtypeCount);
|
||||||
|
annotationsObject.put("ContentsCount", contentsCount);
|
||||||
|
pageInfo.set("Annotations", annotationsObject);
|
||||||
|
|
||||||
|
// Images (simplified)
|
||||||
|
// This part is non-trivial as images can be embedded in multiple ways in a PDF.
|
||||||
|
// Here is a basic structure to recognize image XObjects on a page.
|
||||||
|
ArrayNode imagesArray = objectMapper.createArrayNode();
|
||||||
|
PdfResources resources = itextDoc.getPage(pageNum).getResources();
|
||||||
|
for (PdfName name : resources.getResourceNames()) {
|
||||||
|
PdfObject obj = resources.getResource(name);
|
||||||
|
if (obj instanceof PdfStream) {
|
||||||
|
PdfStream stream = (PdfStream) obj;
|
||||||
|
if (PdfName.Image.equals(stream.getAsName(PdfName.Subtype))) {
|
||||||
|
ObjectNode imageNode = objectMapper.createObjectNode();
|
||||||
|
imageNode.put("Width", stream.getAsNumber(PdfName.Width).intValue());
|
||||||
|
imageNode.put("Height", stream.getAsNumber(PdfName.Height).intValue());
|
||||||
|
PdfObject colorSpace = stream.get(PdfName.ColorSpace);
|
||||||
|
if (colorSpace != null) {
|
||||||
|
imageNode.put("ColorSpace", colorSpace.toString());
|
||||||
|
}
|
||||||
|
imagesArray.add(imageNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pageInfo.set("Images", imagesArray);
|
||||||
|
|
||||||
|
|
||||||
|
// Links
|
||||||
|
ArrayNode linksArray = objectMapper.createArrayNode();
|
||||||
|
Set<String> uniqueURIs = new HashSet<>(); // To store unique URIs
|
||||||
|
|
||||||
|
for (PdfAnnotation annotation : annotations) {
|
||||||
|
if (annotation instanceof PdfLinkAnnotation) {
|
||||||
|
PdfLinkAnnotation linkAnnotation = (PdfLinkAnnotation) annotation;
|
||||||
|
if(linkAnnotation != null && linkAnnotation.getAction() != null) {
|
||||||
|
String uri = linkAnnotation.getAction().toString();
|
||||||
|
uniqueURIs.add(uri); // Add to set to ensure uniqueness
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add unique URIs to linksArray
|
||||||
|
for (String uri : uniqueURIs) {
|
||||||
|
ObjectNode linkNode = objectMapper.createObjectNode();
|
||||||
|
linkNode.put("URI", uri);
|
||||||
|
linksArray.add(linkNode);
|
||||||
|
}
|
||||||
|
pageInfo.set("Links", linksArray);
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
ArrayNode fontsArray = objectMapper.createArrayNode();
|
||||||
|
PdfDictionary fontDicts = resources.getResource(PdfName.Font);
|
||||||
|
Set<String> uniqueSubtypes = new HashSet<>(); // To store unique subtypes
|
||||||
|
|
||||||
|
// Map to store unique fonts and their counts
|
||||||
|
Map<String, ObjectNode> uniqueFontsMap = new HashMap<>();
|
||||||
|
|
||||||
|
if (fontDicts != null) {
|
||||||
|
for (PdfName key : fontDicts.keySet()) {
|
||||||
|
ObjectNode fontNode = objectMapper.createObjectNode(); // Create a new font node for each font
|
||||||
|
PdfDictionary font = fontDicts.getAsDictionary(key);
|
||||||
|
|
||||||
|
boolean isEmbedded = font.containsKey(PdfName.FontFile) ||
|
||||||
|
font.containsKey(PdfName.FontFile2) ||
|
||||||
|
font.containsKey(PdfName.FontFile3);
|
||||||
|
fontNode.put("IsEmbedded", isEmbedded);
|
||||||
|
|
||||||
|
if (font.containsKey(PdfName.Encoding)) {
|
||||||
|
String encoding = font.getAsName(PdfName.Encoding).toString();
|
||||||
|
fontNode.put("Encoding", encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.getAsString(PdfName.BaseFont) != null) {
|
||||||
|
fontNode.put("Name", font.getAsString(PdfName.BaseFont).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String subtype = null;
|
||||||
|
if (font.containsKey(PdfName.Subtype)) {
|
||||||
|
subtype = font.getAsName(PdfName.Subtype).toString();
|
||||||
|
uniqueSubtypes.add(subtype); // Add to set to ensure uniqueness
|
||||||
|
}
|
||||||
|
fontNode.put("Subtype", subtype);
|
||||||
|
|
||||||
|
PdfDictionary fontDescriptor = font.getAsDictionary(PdfName.FontDescriptor);
|
||||||
|
if (fontDescriptor != null) {
|
||||||
|
if (fontDescriptor.containsKey(PdfName.ItalicAngle)) {
|
||||||
|
fontNode.put("ItalicAngle", fontDescriptor.getAsNumber(PdfName.ItalicAngle).floatValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontDescriptor.containsKey(PdfName.Flags)) {
|
||||||
|
int flags = fontDescriptor.getAsNumber(PdfName.Flags).intValue();
|
||||||
|
fontNode.put("IsItalic", (flags & 64) != 0);
|
||||||
|
fontNode.put("IsBold", (flags & 1 << 16) != 0);
|
||||||
|
fontNode.put("IsFixedPitch", (flags & 1) != 0);
|
||||||
|
fontNode.put("IsSerif", (flags & 2) != 0);
|
||||||
|
fontNode.put("IsSymbolic", (flags & 4) != 0);
|
||||||
|
fontNode.put("IsScript", (flags & 8) != 0);
|
||||||
|
fontNode.put("IsNonsymbolic", (flags & 16) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontDescriptor.containsKey(PdfName.FontFamily)) {
|
||||||
|
String fontFamily = fontDescriptor.getAsString(PdfName.FontFamily).toString();
|
||||||
|
fontNode.put("FontFamily", fontFamily);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontDescriptor.containsKey(PdfName.FontStretch)) {
|
||||||
|
String fontStretch = fontDescriptor.getAsName(PdfName.FontStretch).toString();
|
||||||
|
fontNode.put("FontStretch", fontStretch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontDescriptor.containsKey(PdfName.FontBBox)) {
|
||||||
|
PdfArray bbox = fontDescriptor.getAsArray(PdfName.FontBBox);
|
||||||
|
fontNode.put("FontBoundingBox", bbox.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontDescriptor.containsKey(PdfName.FontWeight)) {
|
||||||
|
float fontWeight = fontDescriptor.getAsNumber(PdfName.FontWeight).floatValue();
|
||||||
|
fontNode.put("FontWeight", fontWeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.containsKey(PdfName.ToUnicode)) {
|
||||||
|
fontNode.put("HasToUnicodeMap", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontNode.size() > 0) {
|
||||||
|
// Create a unique key for this font node based on its attributes
|
||||||
|
String uniqueKey = fontNode.toString();
|
||||||
|
|
||||||
|
// Increment count if this font exists, or initialize it if new
|
||||||
|
if (uniqueFontsMap.containsKey(uniqueKey)) {
|
||||||
|
ObjectNode existingFontNode = uniqueFontsMap.get(uniqueKey);
|
||||||
|
int count = existingFontNode.get("Count").asInt() + 1;
|
||||||
|
existingFontNode.put("Count", count);
|
||||||
|
} else {
|
||||||
|
fontNode.put("Count", 1);
|
||||||
|
uniqueFontsMap.put(uniqueKey, fontNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add unique font entries to fontsArray
|
||||||
|
for (ObjectNode uniqueFontNode : uniqueFontsMap.values()) {
|
||||||
|
fontsArray.add(uniqueFontNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pageInfo.set("Fonts", fontsArray);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Access resources dictionary
|
||||||
|
PdfDictionary resourcesDict = itextDoc.getPage(pageNum).getResources().getPdfObject();
|
||||||
|
|
||||||
|
// Color Spaces & ICC Profiles
|
||||||
|
ArrayNode colorSpacesArray = objectMapper.createArrayNode();
|
||||||
|
PdfDictionary colorSpaces = resourcesDict.getAsDictionary(PdfName.ColorSpace);
|
||||||
|
if (colorSpaces != null) {
|
||||||
|
for (PdfName name : colorSpaces.keySet()) {
|
||||||
|
PdfObject colorSpaceObject = colorSpaces.get(name);
|
||||||
|
if (colorSpaceObject instanceof PdfArray) {
|
||||||
|
PdfArray colorSpaceArray = (PdfArray) colorSpaceObject;
|
||||||
|
if (colorSpaceArray.size() > 1 && colorSpaceArray.get(0) instanceof PdfName && PdfName.ICCBased.equals(colorSpaceArray.get(0))) {
|
||||||
|
ObjectNode iccProfileNode = objectMapper.createObjectNode();
|
||||||
|
PdfStream iccStream = (PdfStream) colorSpaceArray.get(1);
|
||||||
|
byte[] iccData = iccStream.getBytes();
|
||||||
|
// TODO: Further decode and analyze the ICC data if needed
|
||||||
|
iccProfileNode.put("ICC Profile Length", iccData.length);
|
||||||
|
colorSpacesArray.add(iccProfileNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pageInfo.set("Color Spaces & ICC Profiles", colorSpacesArray);
|
||||||
|
|
||||||
|
// Other XObjects
|
||||||
|
Map<String, Integer> xObjectCountMap = new HashMap<>(); // To store the count for each type
|
||||||
|
PdfDictionary xObjects = resourcesDict.getAsDictionary(PdfName.XObject);
|
||||||
|
if (xObjects != null) {
|
||||||
|
for (PdfName name : xObjects.keySet()) {
|
||||||
|
PdfStream xObjectStream = xObjects.getAsStream(name);
|
||||||
|
String xObjectType = xObjectStream.getAsName(PdfName.Subtype).toString();
|
||||||
|
|
||||||
|
// Increment the count for this type in the map
|
||||||
|
xObjectCountMap.put(xObjectType, xObjectCountMap.getOrDefault(xObjectType, 0) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the count map to pageInfo (or wherever you want to store it)
|
||||||
|
ObjectNode xObjectCountNode = objectMapper.createObjectNode();
|
||||||
|
for (Map.Entry<String, Integer> entry : xObjectCountMap.entrySet()) {
|
||||||
|
xObjectCountNode.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
pageInfo.set("XObjectCounts", xObjectCountNode);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ArrayNode multimediaArray = objectMapper.createArrayNode();
|
||||||
|
for (PdfAnnotation annotation : annotations) {
|
||||||
|
if (PdfName.RichMedia.equals(annotation.getSubtype())) {
|
||||||
|
ObjectNode multimediaNode = objectMapper.createObjectNode();
|
||||||
|
// Extract details from the dictionary as needed
|
||||||
|
multimediaArray.add(multimediaNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pageInfo.set("Multimedia", multimediaArray);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pageInfoParent.set("Page " + pageNum, pageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
jsonOutput.set("BasicInfo", basicInfo);
|
||||||
|
jsonOutput.set("DocumentInfo", docInfoNode);
|
||||||
|
jsonOutput.set("Compliancy", compliancy);
|
||||||
|
jsonOutput.set("Encryption", encryption);
|
||||||
|
jsonOutput.set("Other", other);
|
||||||
|
jsonOutput.set("PerPageInfo", pageInfoParent);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Save JSON to file
|
||||||
|
String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonOutput);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(jsonString.getBytes(StandardCharsets.UTF_8), "response.json", MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addOutlinesToArray(PdfOutline outline, ArrayNode arrayNode) {
|
||||||
|
if (outline == null) return;
|
||||||
|
ObjectNode outlineNode = objectMapper.createObjectNode();
|
||||||
|
outlineNode.put("Title", outline.getTitle());
|
||||||
|
// You can add other properties if needed
|
||||||
|
arrayNode.add(outlineNode);
|
||||||
|
|
||||||
|
for (PdfOutline child : outline.getAllChildren()) {
|
||||||
|
addOutlinesToArray(child, arrayNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String getPageOrientation(double width, double height) {
|
||||||
|
if (width > height) {
|
||||||
|
return "Landscape";
|
||||||
|
} else if (height > width) {
|
||||||
|
return "Portrait";
|
||||||
|
} else {
|
||||||
|
return "Square";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String getPageSize(double width, double height) {
|
||||||
|
// Common aspect ratios used for standard paper sizes
|
||||||
|
double[] aspectRatios = {4.0 / 3.0, 3.0 / 2.0, Math.sqrt(2.0), 16.0 / 9.0};
|
||||||
|
|
||||||
|
// Check if the page matches any common aspect ratio
|
||||||
|
for (double aspectRatio : aspectRatios) {
|
||||||
|
if (isCloseToAspectRatio(width, height, aspectRatio)) {
|
||||||
|
return "Standard";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not a standard aspect ratio, consider it as a custom size
|
||||||
|
return "Custom";
|
||||||
|
}
|
||||||
|
private boolean isCloseToAspectRatio(double width, double height, double aspectRatio) {
|
||||||
|
// Calculate the aspect ratio of the page
|
||||||
|
double pageAspectRatio = width / height;
|
||||||
|
|
||||||
|
// Compare the page aspect ratio with the common aspect ratio within a threshold
|
||||||
|
return Math.abs(pageAspectRatio - aspectRatio) <= 0.05;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkForStandard(PdfDocument document, String standardKeyword) {
|
||||||
|
// Check Output Intents
|
||||||
|
boolean foundInOutputIntents = checkOutputIntent(document, standardKeyword);
|
||||||
|
if (foundInOutputIntents) return true;
|
||||||
|
|
||||||
|
// Check XMP Metadata (rudimentary)
|
||||||
|
try {
|
||||||
|
byte[] metadataBytes = document.getXmpMetadata();
|
||||||
|
if (metadataBytes != null) {
|
||||||
|
XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(metadataBytes);
|
||||||
|
String xmpString = xmpMeta.dumpObject();
|
||||||
|
if (xmpString.contains(standardKeyword)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (XMPException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean checkOutputIntent(PdfDocument document, String standard) {
|
||||||
|
PdfArray outputIntents = document.getCatalog().getPdfObject().getAsArray(PdfName.OutputIntents);
|
||||||
|
if (outputIntents != null && !outputIntents.isEmpty()) {
|
||||||
|
for (int i = 0; i < outputIntents.size(); i++) {
|
||||||
|
PdfDictionary outputIntentDict = outputIntents.getAsDictionary(i);
|
||||||
|
if (outputIntentDict != null) {
|
||||||
|
PdfString s = outputIntentDict.getAsString(PdfName.S);
|
||||||
|
if (s != null && s.toString().contains(standard)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayNode exploreStructureTree(List<Object> nodes) {
|
||||||
|
ArrayNode elementsArray = objectMapper.createArrayNode();
|
||||||
|
if (nodes != null) {
|
||||||
|
for (Object obj : nodes) {
|
||||||
|
if (obj instanceof PDStructureNode) {
|
||||||
|
PDStructureNode node = (PDStructureNode) obj;
|
||||||
|
ObjectNode elementNode = objectMapper.createObjectNode();
|
||||||
|
|
||||||
|
if (node instanceof PDStructureElement) {
|
||||||
|
PDStructureElement structureElement = (PDStructureElement) node;
|
||||||
|
elementNode.put("Type", structureElement.getStructureType());
|
||||||
|
elementNode.put("Content", getContent(structureElement));
|
||||||
|
|
||||||
|
// Recursively explore child elements
|
||||||
|
ArrayNode childElements = exploreStructureTree(structureElement.getKids());
|
||||||
|
if (childElements.size() > 0) {
|
||||||
|
elementNode.set("Children", childElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elementsArray.add(elementNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elementsArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getContent(PDStructureElement structureElement) {
|
||||||
|
StringBuilder contentBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
for (Object item : structureElement.getKids()) {
|
||||||
|
if (item instanceof COSString) {
|
||||||
|
COSString cosString = (COSString) item;
|
||||||
|
contentBuilder.append(cosString.getString());
|
||||||
|
} else if (item instanceof PDStructureElement) {
|
||||||
|
// For simplicity, we're handling only COSString and PDStructureElement here
|
||||||
|
// but a more comprehensive method would handle other types too
|
||||||
|
contentBuilder.append(getContent((PDStructureElement) item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contentBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String formatDate(Calendar calendar) {
|
||||||
|
if (calendar != null) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
return sdf.format(calendar.getTime());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPageModeDescription(PdfName pageMode) {
|
||||||
|
return pageMode != null ? pageMode.toString().replaceFirst("/", "") : "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,37 +52,37 @@ public class PasswordController {
|
|||||||
@RequestPart(required = true, value = "fileInput")
|
@RequestPart(required = true, value = "fileInput")
|
||||||
@Parameter(description = "The input PDF file to which the password should be added", required = true)
|
@Parameter(description = "The input PDF file to which the password should be added", required = true)
|
||||||
MultipartFile fileInput,
|
MultipartFile fileInput,
|
||||||
@RequestParam(defaultValue = "", name = "ownerPassword")
|
@RequestParam(value = "", name = "ownerPassword", required = false, defaultValue = "")
|
||||||
@Parameter(description = "The owner password to be added to the PDF file (Restricts what can be done with the document once it is opened)")
|
@Parameter(description = "The owner password to be added to the PDF file (Restricts what can be done with the document once it is opened)")
|
||||||
String ownerPassword,
|
String ownerPassword,
|
||||||
@RequestParam(defaultValue = "", name = "password")
|
@RequestParam( name = "password", required = false, defaultValue = "")
|
||||||
@Parameter(description = "The password to be added to the PDF file (Restricts the opening of the document itself.)")
|
@Parameter(description = "The password to be added to the PDF file (Restricts the opening of the document itself.)")
|
||||||
String password,
|
String password,
|
||||||
@RequestParam(defaultValue = "128", name = "keyLength")
|
@RequestParam( name = "keyLength", required = false, defaultValue = "256")
|
||||||
@Parameter(description = "The length of the encryption key", schema = @Schema(allowableValues = {"40", "128", "256"}))
|
@Parameter(description = "The length of the encryption key", schema = @Schema(allowableValues = {"40", "128", "256"}))
|
||||||
int keyLength,
|
int keyLength,
|
||||||
@RequestParam(defaultValue = "false", name = "canAssembleDocument")
|
@RequestParam( name = "canAssembleDocument", required = false)
|
||||||
@Parameter(description = "Whether the document assembly is allowed", example = "false")
|
@Parameter(description = "Whether the document assembly is allowed", example = "false")
|
||||||
boolean canAssembleDocument,
|
boolean canAssembleDocument,
|
||||||
@RequestParam(defaultValue = "false", name = "canExtractContent")
|
@RequestParam( name = "canExtractContent", required = false)
|
||||||
@Parameter(description = "Whether content extraction for accessibility is allowed", example = "false")
|
@Parameter(description = "Whether content extraction for accessibility is allowed", example = "false")
|
||||||
boolean canExtractContent,
|
boolean canExtractContent,
|
||||||
@RequestParam(defaultValue = "false", name = "canExtractForAccessibility")
|
@RequestParam( name = "canExtractForAccessibility", required = false)
|
||||||
@Parameter(description = "Whether content extraction for accessibility is allowed", example = "false")
|
@Parameter(description = "Whether content extraction for accessibility is allowed", example = "false")
|
||||||
boolean canExtractForAccessibility,
|
boolean canExtractForAccessibility,
|
||||||
@RequestParam(defaultValue = "false", name = "canFillInForm")
|
@RequestParam( name = "canFillInForm", required = false)
|
||||||
@Parameter(description = "Whether form filling is allowed", example = "false")
|
@Parameter(description = "Whether form filling is allowed", example = "false")
|
||||||
boolean canFillInForm,
|
boolean canFillInForm,
|
||||||
@RequestParam(defaultValue = "false", name = "canModify")
|
@RequestParam( name = "canModify", required = false)
|
||||||
@Parameter(description = "Whether the document modification is allowed", example = "false")
|
@Parameter(description = "Whether the document modification is allowed", example = "false")
|
||||||
boolean canModify,
|
boolean canModify,
|
||||||
@RequestParam(defaultValue = "false", name = "canModifyAnnotations")
|
@RequestParam( name = "canModifyAnnotations", required = false)
|
||||||
@Parameter(description = "Whether modification of annotations is allowed", example = "false")
|
@Parameter(description = "Whether modification of annotations is allowed", example = "false")
|
||||||
boolean canModifyAnnotations,
|
boolean canModifyAnnotations,
|
||||||
@RequestParam(defaultValue = "false", name = "canPrint")
|
@RequestParam(name = "canPrint", required = false)
|
||||||
@Parameter(description = "Whether printing of the document is allowed", example = "false")
|
@Parameter(description = "Whether printing of the document is allowed", example = "false")
|
||||||
boolean canPrint,
|
boolean canPrint,
|
||||||
@RequestParam(defaultValue = "false", name = "canPrintFaithful")
|
@RequestParam( name = "canPrintFaithful", required = false)
|
||||||
@Parameter(description = "Whether faithful printing is allowed", example = "false")
|
@Parameter(description = "Whether faithful printing is allowed", example = "false")
|
||||||
boolean canPrintFaithful
|
boolean canPrintFaithful
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
@@ -99,14 +99,14 @@ public class PasswordController {
|
|||||||
ap.setCanPrintFaithful(!canPrintFaithful);
|
ap.setCanPrintFaithful(!canPrintFaithful);
|
||||||
StandardProtectionPolicy spp = new StandardProtectionPolicy(ownerPassword, password, ap);
|
StandardProtectionPolicy spp = new StandardProtectionPolicy(ownerPassword, password, ap);
|
||||||
|
|
||||||
|
if(!"".equals(ownerPassword) || !"".equals(password)) {
|
||||||
|
spp.setEncryptionKeyLength(keyLength);
|
||||||
spp.setEncryptionKeyLength(keyLength);
|
}
|
||||||
|
|
||||||
spp.setPermissions(ap);
|
spp.setPermissions(ap);
|
||||||
|
|
||||||
document.protect(spp);
|
document.protect(spp);
|
||||||
|
|
||||||
|
if("".equals(ownerPassword) && "".equals(password))
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_permissions.pdf");
|
||||||
return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
|
return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.security;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
|
import org.apache.pdfbox.rendering.ImageType;
|
||||||
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import stirling.software.SPDF.model.PDFText;
|
||||||
|
import stirling.software.SPDF.pdf.TextFinder;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
|
public class RedactController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(RedactController.class);
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping(value = "/auto-redact", consumes = "multipart/form-data")
|
||||||
|
@Operation(summary = "Redacts listOfText in a PDF document",
|
||||||
|
description = "This operation takes an input PDF file and redacts the provided listOfText. Input:PDF, Output:PDF, Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> redactPdf(
|
||||||
|
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
||||||
|
@Parameter(description = "List of listOfText to redact from the PDF", required = true, schema = @Schema(type = "string")) @RequestParam("listOfText") String listOfTextString,
|
||||||
|
@RequestParam(value = "useRegex", required = false) boolean useRegex,
|
||||||
|
@RequestParam(value = "wholeWordSearch", required = false) boolean wholeWordSearchBool,
|
||||||
|
@RequestParam(value = "customPadding", required = false) float customPadding,
|
||||||
|
@RequestParam(value = "convertPDFToImage", required = false) boolean convertPDFToImage) throws Exception {
|
||||||
|
|
||||||
|
System.out.println(listOfTextString);
|
||||||
|
String[] listOfText = listOfTextString.split("\n");
|
||||||
|
byte[] bytes = file.getBytes();
|
||||||
|
PDDocument document = PDDocument.load(new ByteArrayInputStream(bytes));
|
||||||
|
for (String text : listOfText) {
|
||||||
|
text = text.trim();
|
||||||
|
System.out.println(text);
|
||||||
|
TextFinder textFinder = new TextFinder(text, useRegex, wholeWordSearchBool);
|
||||||
|
List<PDFText> foundTexts = textFinder.getTextLocations(document);
|
||||||
|
redactFoundText(document, foundTexts, customPadding);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (convertPDFToImage) {
|
||||||
|
PDDocument imageDocument = new PDDocument();
|
||||||
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
|
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
||||||
|
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
|
||||||
|
PDPage newPage = new PDPage(new PDRectangle(bim.getWidth(), bim.getHeight()));
|
||||||
|
imageDocument.addPage(newPage);
|
||||||
|
PDImageXObject pdImage = LosslessFactory.createFromImage(imageDocument, bim);
|
||||||
|
PDPageContentStream contentStream = new PDPageContentStream(imageDocument, newPage);
|
||||||
|
contentStream.drawImage(pdImage, 0, 0);
|
||||||
|
contentStream.close();
|
||||||
|
}
|
||||||
|
document.close();
|
||||||
|
document = imageDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
document.save(baos);
|
||||||
|
document.close();
|
||||||
|
|
||||||
|
byte[] pdfContent = baos.toByteArray();
|
||||||
|
return WebResponseUtils.bytesToWebResponse(pdfContent,
|
||||||
|
file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_redacted.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void redactFoundText(PDDocument document, List<PDFText> blocks, float customPadding) throws IOException {
|
||||||
|
var allPages = document.getDocumentCatalog().getPages();
|
||||||
|
|
||||||
|
for (PDFText block : blocks) {
|
||||||
|
var page = allPages.get(block.getPageIndex());
|
||||||
|
PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||||
|
contentStream.setNonStrokingColor(Color.BLACK);
|
||||||
|
float padding = (block.getY2() - block.getY1()) * 0.3f + customPadding;
|
||||||
|
PDRectangle pageBox = page.getBBox();
|
||||||
|
contentStream.addRect(block.getX1(), pageBox.getHeight() - block.getY1() - padding, block.getX2() - block.getX1(), block.getY2() - block.getY1() + 2 * padding);
|
||||||
|
contentStream.fill();
|
||||||
|
contentStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.security;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.cos.COSDictionary;
|
||||||
|
import org.apache.pdfbox.cos.COSName;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDResources;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.action.PDActionLaunch;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class SanitizeController {
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/sanitize-pdf")
|
||||||
|
@Operation(summary = "Sanitize a PDF file",
|
||||||
|
description = "This endpoint processes a PDF file and removes specific elements based on the provided options. Input:PDF Output:PDF Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> sanitizePDF(
|
||||||
|
@RequestPart(required = true, value = "fileInput")
|
||||||
|
@Parameter(description = "The input PDF file to be sanitized")
|
||||||
|
MultipartFile inputFile,
|
||||||
|
@RequestParam(name = "removeJavaScript", required = false, defaultValue = "false")
|
||||||
|
@Parameter(description = "Remove JavaScript actions from the PDF if set to true")
|
||||||
|
Boolean removeJavaScript,
|
||||||
|
@RequestParam(name = "removeEmbeddedFiles", required = false, defaultValue = "false")
|
||||||
|
@Parameter(description = "Remove embedded files from the PDF if set to true")
|
||||||
|
Boolean removeEmbeddedFiles,
|
||||||
|
@RequestParam(name = "removeMetadata", required = false, defaultValue = "false")
|
||||||
|
@Parameter(description = "Remove metadata from the PDF if set to true")
|
||||||
|
Boolean removeMetadata,
|
||||||
|
@RequestParam(name = "removeLinks", required = false, defaultValue = "false")
|
||||||
|
@Parameter(description = "Remove links from the PDF if set to true")
|
||||||
|
Boolean removeLinks,
|
||||||
|
@RequestParam(name = "removeFonts", required = false, defaultValue = "false")
|
||||||
|
@Parameter(description = "Remove fonts from the PDF if set to true")
|
||||||
|
Boolean removeFonts) throws IOException {
|
||||||
|
|
||||||
|
try (PDDocument document = PDDocument.load(inputFile.getInputStream())) {
|
||||||
|
if (removeJavaScript) {
|
||||||
|
sanitizeJavaScript(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeEmbeddedFiles) {
|
||||||
|
sanitizeEmbeddedFiles(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeMetadata) {
|
||||||
|
sanitizeMetadata(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeLinks) {
|
||||||
|
sanitizeLinks(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeFonts) {
|
||||||
|
sanitizeFonts(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(document, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_sanitized.pdf");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void sanitizeJavaScript(PDDocument document) throws IOException {
|
||||||
|
// Get the root dictionary (catalog) of the PDF
|
||||||
|
PDDocumentCatalog catalog = document.getDocumentCatalog();
|
||||||
|
|
||||||
|
// Get the Names dictionary
|
||||||
|
COSDictionary namesDict = (COSDictionary) catalog.getCOSObject().getDictionaryObject(COSName.NAMES);
|
||||||
|
|
||||||
|
if (namesDict != null) {
|
||||||
|
// Get the JavaScript dictionary
|
||||||
|
COSDictionary javaScriptDict = (COSDictionary) namesDict.getDictionaryObject(COSName.getPDFName("JavaScript"));
|
||||||
|
|
||||||
|
if (javaScriptDict != null) {
|
||||||
|
// Remove the JavaScript dictionary
|
||||||
|
namesDict.removeItem(COSName.getPDFName("JavaScript"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PDPage page : document.getPages()) {
|
||||||
|
for (PDAnnotation annotation : page.getAnnotations()) {
|
||||||
|
if (annotation instanceof PDAnnotationWidget) {
|
||||||
|
PDAnnotationWidget widget = (PDAnnotationWidget) annotation;
|
||||||
|
PDAction action = widget.getAction();
|
||||||
|
if (action instanceof PDActionJavaScript) {
|
||||||
|
widget.setAction(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
|
||||||
|
if (acroForm != null) {
|
||||||
|
for (PDField field : acroForm.getFields()) {
|
||||||
|
PDFormFieldAdditionalActions actions = field.getActions();
|
||||||
|
if(actions != null) {
|
||||||
|
if (actions.getC() instanceof PDActionJavaScript) {
|
||||||
|
actions.setC(null);
|
||||||
|
}
|
||||||
|
if (actions.getF() instanceof PDActionJavaScript) {
|
||||||
|
actions.setF(null);
|
||||||
|
}
|
||||||
|
if (actions.getK() instanceof PDActionJavaScript) {
|
||||||
|
actions.setK(null);
|
||||||
|
}
|
||||||
|
if (actions.getV() instanceof PDActionJavaScript) {
|
||||||
|
actions.setV(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void sanitizeEmbeddedFiles(PDDocument document) {
|
||||||
|
PDPageTree allPages = document.getPages();
|
||||||
|
|
||||||
|
for (PDPage page : allPages) {
|
||||||
|
PDResources res = page.getResources();
|
||||||
|
|
||||||
|
// Remove embedded files from the PDF
|
||||||
|
res.getCOSObject().removeItem(COSName.getPDFName("EmbeddedFiles"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void sanitizeMetadata(PDDocument document) {
|
||||||
|
PDMetadata metadata = document.getDocumentCatalog().getMetadata();
|
||||||
|
if (metadata != null) {
|
||||||
|
document.getDocumentCatalog().setMetadata(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void sanitizeLinks(PDDocument document) throws IOException {
|
||||||
|
for (PDPage page : document.getPages()) {
|
||||||
|
for (PDAnnotation annotation : page.getAnnotations()) {
|
||||||
|
if (annotation instanceof PDAnnotationLink) {
|
||||||
|
PDAction action = ((PDAnnotationLink) annotation).getAction();
|
||||||
|
if (action instanceof PDActionLaunch || action instanceof PDActionURI) {
|
||||||
|
((PDAnnotationLink) annotation).setAction(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sanitizeFonts(PDDocument document) {
|
||||||
|
for (PDPage page : document.getPages()) {
|
||||||
|
page.getResources().getCOSObject().removeItem(COSName.getPDFName("Font"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package stirling.software.SPDF.controller.api.security;
|
package stirling.software.SPDF.controller.api.security;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
@@ -15,6 +16,8 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|||||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||||
import org.apache.pdfbox.util.Matrix;
|
import org.apache.pdfbox.util.Matrix;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
@@ -27,127 +30,167 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class WatermarkController {
|
public class WatermarkController {
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
|
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
|
||||||
@Operation(summary = "Add watermark to a PDF file",
|
@Operation(summary = "Add watermark to a PDF file", description = "This endpoint adds a watermark to a given PDF file. Users can specify the watermark type (text or image), rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO")
|
||||||
description = "This endpoint adds a watermark to a given PDF file. Users can specify the watermark text, font size, rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO")
|
public ResponseEntity<byte[]> addWatermark(
|
||||||
public ResponseEntity<byte[]> addWatermark(
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to add a watermark") MultipartFile pdfFile,
|
||||||
@RequestPart(required = true, value = "fileInput")
|
@RequestParam(required = true) @Parameter(description = "The watermark type (text or image)") String watermarkType,
|
||||||
@Parameter(description = "The input PDF file to add a watermark")
|
@RequestParam(required = false) @Parameter(description = "The watermark text") String watermarkText,
|
||||||
MultipartFile pdfFile,
|
@RequestPart(required = false) @Parameter(description = "The watermark image") MultipartFile watermarkImage,
|
||||||
@RequestParam(defaultValue = "roman", name = "alphabet")
|
|
||||||
@Parameter(description = "The selected alphabet",
|
|
||||||
schema = @Schema(type = "string",
|
|
||||||
allowableValues = {"roman","arabic","japanese","korean","chinese"},
|
|
||||||
defaultValue = "roman"))
|
|
||||||
String alphabet,
|
|
||||||
@RequestParam("watermarkText")
|
|
||||||
@Parameter(description = "The watermark text to add to the PDF file")
|
|
||||||
String watermarkText,
|
|
||||||
@RequestParam(defaultValue = "30", name = "fontSize")
|
|
||||||
@Parameter(description = "The font size of the watermark text", example = "30")
|
|
||||||
float fontSize,
|
|
||||||
@RequestParam(defaultValue = "0", name = "rotation")
|
|
||||||
@Parameter(description = "The rotation of the watermark text in degrees", example = "0")
|
|
||||||
float rotation,
|
|
||||||
@RequestParam(defaultValue = "0.5", name = "opacity")
|
|
||||||
@Parameter(description = "The opacity of the watermark text (0.0 - 1.0)", example = "0.5")
|
|
||||||
float opacity,
|
|
||||||
@RequestParam(defaultValue = "50", name = "widthSpacer")
|
|
||||||
@Parameter(description = "The width spacer between watermark texts", example = "50")
|
|
||||||
int widthSpacer,
|
|
||||||
@RequestParam(defaultValue = "50", name = "heightSpacer")
|
|
||||||
@Parameter(description = "The height spacer between watermark texts", example = "50")
|
|
||||||
int heightSpacer) throws IOException, Exception {
|
|
||||||
|
|
||||||
// Load the input PDF
|
@RequestParam(defaultValue = "roman", name = "alphabet") @Parameter(description = "The selected alphabet",
|
||||||
PDDocument document = PDDocument.load(pdfFile.getInputStream());
|
schema = @Schema(type = "string",
|
||||||
String producer = document.getDocumentInformation().getProducer();
|
allowableValues = {"roman","arabic","japanese","korean","chinese"},
|
||||||
// Create a page in the document
|
defaultValue = "roman")) String alphabet,
|
||||||
for (PDPage page : document.getPages()) {
|
@RequestParam(defaultValue = "30", name = "fontSize") @Parameter(description = "The font size of the watermark text", example = "30") float fontSize,
|
||||||
|
@RequestParam(defaultValue = "0", name = "rotation") @Parameter(description = "The rotation of the watermark in degrees", example = "0") float rotation,
|
||||||
|
@RequestParam(defaultValue = "0.5", name = "opacity") @Parameter(description = "The opacity of the watermark (0.0 - 1.0)", example = "0.5") float opacity,
|
||||||
|
@RequestParam(defaultValue = "50", name = "widthSpacer") @Parameter(description = "The width spacer between watermark elements", example = "50") int widthSpacer,
|
||||||
|
@RequestParam(defaultValue = "50", name = "heightSpacer") @Parameter(description = "The height spacer between watermark elements", example = "50") int heightSpacer)
|
||||||
|
throws IOException, Exception {
|
||||||
|
|
||||||
// Get the page's content stream
|
// Load the input PDF
|
||||||
PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true);
|
PDDocument document = PDDocument.load(pdfFile.getInputStream());
|
||||||
|
|
||||||
// Set transparency
|
// Create a page in the document
|
||||||
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
|
for (PDPage page : document.getPages()) {
|
||||||
graphicsState.setNonStrokingAlphaConstant(opacity);
|
|
||||||
contentStream.setGraphicsStateParameters(graphicsState);
|
// Get the page's content stream
|
||||||
|
PDPageContentStream contentStream = new PDPageContentStream(document, page,
|
||||||
|
PDPageContentStream.AppendMode.APPEND, true);
|
||||||
|
|
||||||
|
// Set transparency
|
||||||
|
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
|
||||||
|
graphicsState.setNonStrokingAlphaConstant(opacity);
|
||||||
|
contentStream.setGraphicsStateParameters(graphicsState);
|
||||||
|
|
||||||
|
if (watermarkType.equalsIgnoreCase("text")) {
|
||||||
|
addTextWatermark(contentStream, watermarkText, document, page, rotation, widthSpacer, heightSpacer,
|
||||||
|
fontSize, alphabet);
|
||||||
|
} else if (watermarkType.equalsIgnoreCase("image")) {
|
||||||
|
addImageWatermark(contentStream, watermarkImage, document, page, rotation, widthSpacer, heightSpacer,
|
||||||
|
fontSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the content stream
|
||||||
|
contentStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(document,
|
||||||
|
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTextWatermark(PDPageContentStream contentStream, String watermarkText, PDDocument document,
|
||||||
|
PDPage page, float rotation, int widthSpacer, int heightSpacer, float fontSize, String alphabet) throws IOException {
|
||||||
|
String resourceDir = "";
|
||||||
|
PDFont font = PDType1Font.HELVETICA_BOLD;
|
||||||
|
switch (alphabet) {
|
||||||
|
case "arabic":
|
||||||
|
resourceDir = "static/fonts/NotoSansArabic-Regular.ttf";
|
||||||
|
break;
|
||||||
|
case "japanese":
|
||||||
|
resourceDir = "static/fonts/Meiryo.ttf";
|
||||||
|
break;
|
||||||
|
case "korean":
|
||||||
|
resourceDir = "static/fonts/malgun.ttf";
|
||||||
|
break;
|
||||||
|
case "chinese":
|
||||||
|
resourceDir = "static/fonts/SimSun.ttf";
|
||||||
|
break;
|
||||||
|
case "roman":
|
||||||
|
default:
|
||||||
|
resourceDir = "static/fonts/NotoSans-Regular.ttf";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String resourceDir = "";
|
if(!resourceDir.equals("")) {
|
||||||
PDFont font = PDType1Font.HELVETICA_BOLD;
|
ClassPathResource classPathResource = new ClassPathResource(resourceDir);
|
||||||
switch (alphabet) {
|
String fileExtension = resourceDir.substring(resourceDir.lastIndexOf("."));
|
||||||
case "arabic":
|
File tempFile = File.createTempFile("NotoSansFont", fileExtension);
|
||||||
resourceDir = "static/fonts/NotoSansArabic-Regular.ttf";
|
try (InputStream is = classPathResource.getInputStream(); FileOutputStream os = new FileOutputStream(tempFile)) {
|
||||||
break;
|
IOUtils.copy(is, os);
|
||||||
case "japanese":
|
|
||||||
resourceDir = "static/fonts/Meiryo.ttf";
|
|
||||||
break;
|
|
||||||
case "korean":
|
|
||||||
resourceDir = "static/fonts/malgun.ttf";
|
|
||||||
break;
|
|
||||||
case "chinese":
|
|
||||||
resourceDir = "static/fonts/SimSun.ttf";
|
|
||||||
break;
|
|
||||||
case "roman":
|
|
||||||
default:
|
|
||||||
resourceDir = "static/fonts/NotoSans-Regular.ttf";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(!resourceDir.equals("")) {
|
|
||||||
ClassPathResource classPathResource = new ClassPathResource(resourceDir);
|
|
||||||
String fileExtension = resourceDir.substring(resourceDir.lastIndexOf("."));
|
|
||||||
File tempFile = File.createTempFile("NotoSansFont", fileExtension);
|
|
||||||
try (InputStream is = classPathResource.getInputStream(); FileOutputStream os = new FileOutputStream(tempFile)) {
|
|
||||||
IOUtils.copy(is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
font = PDType0Font.load(document, tempFile);
|
|
||||||
tempFile.deleteOnExit();
|
|
||||||
}
|
}
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.setFont(font, fontSize);
|
|
||||||
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
|
|
||||||
|
|
||||||
// Set size and location of watermark
|
font = PDType0Font.load(document, tempFile);
|
||||||
float pageWidth = page.getMediaBox().getWidth();
|
tempFile.deleteOnExit();
|
||||||
float pageHeight = page.getMediaBox().getHeight();
|
|
||||||
float watermarkWidth = widthSpacer + font.getStringWidth(watermarkText) * fontSize / 1000;
|
|
||||||
float watermarkHeight = heightSpacer + fontSize;
|
|
||||||
int watermarkRows = (int) (pageHeight / watermarkHeight + 1);
|
|
||||||
int watermarkCols = (int) (pageWidth / watermarkWidth + 1);
|
|
||||||
|
|
||||||
// Add the watermark text
|
|
||||||
for (int i = 0; i < watermarkRows; i++) {
|
|
||||||
for (int j = 0; j < watermarkCols; j++) {
|
|
||||||
|
|
||||||
if(producer.contains("Google Docs")) {
|
|
||||||
//This fixes weird unknown google docs y axis rotation/flip issue
|
|
||||||
//TODO: Long term fix one day
|
|
||||||
//contentStream.setTextMatrix(1, 0, 0, -1, j * watermarkWidth, pageHeight - i * watermarkHeight);
|
|
||||||
Matrix matrix = new Matrix(1, 0, 0, -1, j * watermarkWidth, pageHeight - i * watermarkHeight);
|
|
||||||
contentStream.setTextMatrix(matrix);
|
|
||||||
} else {
|
|
||||||
contentStream.setTextMatrix(Matrix.getRotateInstance((float) Math.toRadians(rotation), j * watermarkWidth, i * watermarkHeight));
|
|
||||||
}
|
|
||||||
contentStream.showTextWithPositioning(new Object[] { watermarkText });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
// Close the content stream
|
|
||||||
contentStream.close();
|
|
||||||
}
|
}
|
||||||
return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
|
|
||||||
}
|
contentStream.setFont(font, fontSize);
|
||||||
|
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
|
||||||
|
|
||||||
|
// Set size and location of text watermark
|
||||||
|
float watermarkWidth = widthSpacer + font.getStringWidth(watermarkText) * fontSize / 1000;
|
||||||
|
float watermarkHeight = heightSpacer + fontSize;
|
||||||
|
float pageWidth = page.getMediaBox().getWidth();
|
||||||
|
float pageHeight = page.getMediaBox().getHeight();
|
||||||
|
int watermarkRows = (int) (pageHeight / watermarkHeight + 1);
|
||||||
|
int watermarkCols = (int) (pageWidth / watermarkWidth + 1);
|
||||||
|
|
||||||
|
// Add the text watermark
|
||||||
|
for (int i = 0; i < watermarkRows; i++) {
|
||||||
|
for (int j = 0; j < watermarkCols; j++) {
|
||||||
|
contentStream.beginText();
|
||||||
|
contentStream.setTextMatrix(Matrix.getRotateInstance((float) Math.toRadians(rotation),
|
||||||
|
j * watermarkWidth, i * watermarkHeight));
|
||||||
|
contentStream.showText(watermarkText);
|
||||||
|
contentStream.endText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addImageWatermark(PDPageContentStream contentStream, MultipartFile watermarkImage, PDDocument document, PDPage page, float rotation,
|
||||||
|
int widthSpacer, int heightSpacer, float fontSize) throws IOException {
|
||||||
|
|
||||||
|
// Load the watermark image
|
||||||
|
BufferedImage image = ImageIO.read(watermarkImage.getInputStream());
|
||||||
|
|
||||||
|
// Compute width based on original aspect ratio
|
||||||
|
float aspectRatio = (float) image.getWidth() / (float) image.getHeight();
|
||||||
|
|
||||||
|
// Desired physical height (in PDF points)
|
||||||
|
float desiredPhysicalHeight = fontSize ;
|
||||||
|
|
||||||
|
// Desired physical width based on the aspect ratio
|
||||||
|
float desiredPhysicalWidth = desiredPhysicalHeight * aspectRatio;
|
||||||
|
|
||||||
|
// Convert the BufferedImage to PDImageXObject
|
||||||
|
PDImageXObject xobject = LosslessFactory.createFromImage(document, image);
|
||||||
|
|
||||||
|
// Calculate the number of rows and columns for watermarks
|
||||||
|
float pageWidth = page.getMediaBox().getWidth();
|
||||||
|
float pageHeight = page.getMediaBox().getHeight();
|
||||||
|
int watermarkRows = (int) ((pageHeight + heightSpacer) / (desiredPhysicalHeight + heightSpacer));
|
||||||
|
int watermarkCols = (int) ((pageWidth + widthSpacer) / (desiredPhysicalWidth + widthSpacer));
|
||||||
|
|
||||||
|
for (int i = 0; i < watermarkRows; i++) {
|
||||||
|
for (int j = 0; j < watermarkCols; j++) {
|
||||||
|
float x = j * (desiredPhysicalWidth + widthSpacer);
|
||||||
|
float y = i * (desiredPhysicalHeight + heightSpacer);
|
||||||
|
|
||||||
|
// Save the graphics state
|
||||||
|
contentStream.saveGraphicsState();
|
||||||
|
|
||||||
|
// Create rotation matrix and rotate
|
||||||
|
contentStream.transform(Matrix.getTranslateInstance(x + desiredPhysicalWidth / 2, y + desiredPhysicalHeight / 2));
|
||||||
|
contentStream.transform(Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0));
|
||||||
|
contentStream.transform(Matrix.getTranslateInstance(-desiredPhysicalWidth / 2, -desiredPhysicalHeight / 2));
|
||||||
|
|
||||||
|
// Draw the image and restore the graphics state
|
||||||
|
contentStream.drawImage(xobject, 0, 0, desiredPhysicalWidth, desiredPhysicalHeight);
|
||||||
|
contentStream.restoreGraphicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package stirling.software.SPDF.controller.web;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
|
import stirling.software.SPDF.model.User;
|
||||||
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
|
@Controller
|
||||||
|
@Tag(name = "Account Security", description = "Account Security APIs")
|
||||||
|
public class AccountWebController {
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/login")
|
||||||
|
public String login(HttpServletRequest request, Model model, Authentication authentication) {
|
||||||
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getParameter("error") != null) {
|
||||||
|
|
||||||
|
model.addAttribute("error", request.getParameter("error"));
|
||||||
|
}
|
||||||
|
if (request.getParameter("logout") != null) {
|
||||||
|
|
||||||
|
model.addAttribute("logoutMessage", "You have been logged out.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository; // Assuming you have a repository for user operations
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserService userService; // Assuming you have a repository for user operations
|
||||||
|
|
||||||
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
|
@GetMapping("/addUsers")
|
||||||
|
public String showAddUserForm(Model model) {
|
||||||
|
List<User> allUsers = userRepository.findAll();
|
||||||
|
model.addAttribute("users", allUsers);
|
||||||
|
return "addUsers";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/account")
|
||||||
|
public String account(HttpServletRequest request, Model model, Authentication authentication) {
|
||||||
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
|
Object principal = authentication.getPrincipal();
|
||||||
|
|
||||||
|
if (principal instanceof UserDetails) {
|
||||||
|
// Cast the principal object to UserDetails
|
||||||
|
UserDetails userDetails = (UserDetails) principal;
|
||||||
|
|
||||||
|
// Retrieve username and other attributes
|
||||||
|
String username = userDetails.getUsername();
|
||||||
|
|
||||||
|
// Fetch user details from the database
|
||||||
|
Optional<User> user = userRepository.findByUsername(username); // Assuming findByUsername method exists
|
||||||
|
if (!user.isPresent()) {
|
||||||
|
// Handle error appropriately
|
||||||
|
return "redirect:/error"; // Example redirection in case of error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert settings map to JSON string
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
String settingsJson;
|
||||||
|
try {
|
||||||
|
settingsJson = objectMapper.writeValueAsString(user.get().getSettings());
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
// Handle JSON conversion error
|
||||||
|
e.printStackTrace();
|
||||||
|
return "redirect:/error"; // Example redirection in case of error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add attributes to the model
|
||||||
|
model.addAttribute("username", username);
|
||||||
|
model.addAttribute("role", user.get().getRolesAsString());
|
||||||
|
model.addAttribute("settings", settingsJson);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
return "account";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,6 +19,27 @@ public class ConverterWebController {
|
|||||||
return "convert/img-to-pdf";
|
return "convert/img-to-pdf";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/html-to-pdf")
|
||||||
|
@Hidden
|
||||||
|
public String convertHTMLToPdfForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "html-to-pdf");
|
||||||
|
return "convert/html-to-pdf";
|
||||||
|
}
|
||||||
|
@GetMapping("/markdown-to-pdf")
|
||||||
|
@Hidden
|
||||||
|
public String convertMarkdownToPdfForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "markdown-to-pdf");
|
||||||
|
return "convert/markdown-to-pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/url-to-pdf")
|
||||||
|
@Hidden
|
||||||
|
public String convertURLToPdfForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "url-to-pdf");
|
||||||
|
return "convert/url-to-pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/pdf-to-img")
|
@GetMapping("/pdf-to-img")
|
||||||
@Hidden
|
@Hidden
|
||||||
|
|||||||
@@ -1,22 +1,76 @@
|
|||||||
package stirling.software.SPDF.controller.web;
|
package stirling.software.SPDF.controller.web;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Hidden;
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class GeneralWebController {
|
public class GeneralWebController {
|
||||||
@GetMapping("/pipeline")
|
|
||||||
@Hidden
|
|
||||||
public String pipelineForm(Model model) {
|
|
||||||
model.addAttribute("currentPage", "pipeline");
|
|
||||||
return "pipeline";
|
@GetMapping("/pipeline")
|
||||||
|
@Hidden
|
||||||
|
public String pipelineForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "pipeline");
|
||||||
|
|
||||||
|
List<String> pipelineConfigs = new ArrayList<>();
|
||||||
|
try (Stream<Path> paths = Files.walk(Paths.get("./pipeline/defaultWebUIConfigs/"))) {
|
||||||
|
List<Path> jsonFiles = paths
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.filter(p -> p.toString().endsWith(".json"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
for (Path jsonFile : jsonFiles) {
|
||||||
|
String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
|
||||||
|
pipelineConfigs.add(content);
|
||||||
|
}
|
||||||
|
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
|
||||||
|
for (String config : pipelineConfigs) {
|
||||||
|
Map<String, Object> jsonContent = new ObjectMapper().readValue(config, Map.class);
|
||||||
|
String name = (String) jsonContent.get("name");
|
||||||
|
Map<String, String> configWithName = new HashMap<>();
|
||||||
|
configWithName.put("json", config);
|
||||||
|
configWithName.put("name", name);
|
||||||
|
pipelineConfigsWithNames.add(configWithName);
|
||||||
|
}
|
||||||
|
model.addAttribute("pipelineConfigsWithNames", pipelineConfigsWithNames);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.addAttribute("pipelineConfigs", pipelineConfigs);
|
||||||
|
|
||||||
|
return "pipeline";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/merge-pdfs")
|
@GetMapping("/merge-pdfs")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String mergePdfForm(Model model) {
|
public String mergePdfForm(Model model) {
|
||||||
@@ -47,6 +101,20 @@ public class GeneralWebController {
|
|||||||
return "pdf-organizer";
|
return "pdf-organizer";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/extract-page")
|
||||||
|
@Hidden
|
||||||
|
public String extractPages(Model model) {
|
||||||
|
model.addAttribute("currentPage", "extract-page");
|
||||||
|
return "extract-page";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/pdf-to-single-page")
|
||||||
|
@Hidden
|
||||||
|
public String pdfToSinglePage(Model model) {
|
||||||
|
model.addAttribute("currentPage", "pdf-to-single-page");
|
||||||
|
return "pdf-to-single-page";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/rotate-pdf")
|
@GetMapping("/rotate-pdf")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String rotatePdfForm(Model model) {
|
public String rotatePdfForm(Model model) {
|
||||||
@@ -65,7 +133,47 @@ public class GeneralWebController {
|
|||||||
@Hidden
|
@Hidden
|
||||||
public String signForm(Model model) {
|
public String signForm(Model model) {
|
||||||
model.addAttribute("currentPage", "sign");
|
model.addAttribute("currentPage", "sign");
|
||||||
|
model.addAttribute("fonts", getFontNames());
|
||||||
return "sign";
|
return "sign";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
|
||||||
|
private List<String> getFontNames() {
|
||||||
|
try {
|
||||||
|
Resource[] resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader)
|
||||||
|
.getResources("classpath:static/fonts/*.woff2");
|
||||||
|
|
||||||
|
return Arrays.stream(resources)
|
||||||
|
.map(resource -> {
|
||||||
|
try {
|
||||||
|
String filename = resource.getFilename();
|
||||||
|
return filename.substring(0, filename.length() - 6); // Remove .woff2 extension
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Error processing filename", e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to read font directory", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/crop")
|
||||||
|
@Hidden
|
||||||
|
public String cropForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "crop");
|
||||||
|
return "crop";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/auto-split-pdf")
|
||||||
|
@Hidden
|
||||||
|
public String autoSPlitPDFForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "auto-split-pdf");
|
||||||
|
return "auto-split-pdf";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller.web;
|
package stirling.software.SPDF.controller.web;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
@@ -7,6 +8,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Hidden;
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class HomeWebController {
|
public class HomeWebController {
|
||||||
@@ -31,18 +33,16 @@ public class HomeWebController {
|
|||||||
return "redirect:/";
|
return "redirect:/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
|
||||||
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
|
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@Hidden
|
@Hidden
|
||||||
public String getRobotsTxt() {
|
public String getRobotsTxt() {
|
||||||
String allowGoogleVisibility = System.getProperty("ALLOW_GOOGLE_VISIBILITY");
|
Boolean allowGoogle = applicationProperties.getSystem().getGooglevisibility();
|
||||||
if (allowGoogleVisibility == null)
|
if(Boolean.TRUE.equals(allowGoogle)) {
|
||||||
allowGoogleVisibility = System.getenv("ALLOW_GOOGLE_VISIBILITY");
|
|
||||||
if (allowGoogleVisibility == null)
|
|
||||||
allowGoogleVisibility = "false";
|
|
||||||
if (Boolean.parseBoolean(allowGoogleVisibility)) {
|
|
||||||
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nAllow: /";
|
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nAllow: /";
|
||||||
} else {
|
} else {
|
||||||
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
|
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
package stirling.software.SPDF.controller.web;
|
package stirling.software.SPDF.controller.web;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
@@ -14,14 +22,32 @@ import io.micrometer.core.instrument.MeterRegistry;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import stirling.software.SPDF.config.StartupApplicationListener;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1")
|
@RequestMapping("/api/v1")
|
||||||
@Tag(name = "API", description = "Info APIs")
|
@Tag(name = "API", description = "Info APIs")
|
||||||
public class MetricsController {
|
public class MetricsController {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
|
||||||
private final MeterRegistry meterRegistry;
|
private final MeterRegistry meterRegistry;
|
||||||
|
|
||||||
|
private boolean metricsEnabled;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
Boolean metricsEnabled = applicationProperties.getMetrics().getEnabled();
|
||||||
|
if(metricsEnabled == null)
|
||||||
|
metricsEnabled = true;
|
||||||
|
this.metricsEnabled = metricsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
public MetricsController(MeterRegistry meterRegistry) {
|
public MetricsController(MeterRegistry meterRegistry) {
|
||||||
this.meterRegistry = meterRegistry;
|
this.meterRegistry = meterRegistry;
|
||||||
}
|
}
|
||||||
@@ -29,18 +55,25 @@ public class MetricsController {
|
|||||||
@GetMapping("/status")
|
@GetMapping("/status")
|
||||||
@Operation(summary = "Application status and version",
|
@Operation(summary = "Application status and version",
|
||||||
description = "This endpoint returns the status of the application and its version number.")
|
description = "This endpoint returns the status of the application and its version number.")
|
||||||
public Map<String, String> getStatus() {
|
public ResponseEntity<?> getStatus() {
|
||||||
|
if (!metricsEnabled) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, String> status = new HashMap<>();
|
Map<String, String> status = new HashMap<>();
|
||||||
status.put("status", "UP");
|
status.put("status", "UP");
|
||||||
status.put("version", getClass().getPackage().getImplementationVersion());
|
status.put("version", getClass().getPackage().getImplementationVersion());
|
||||||
return status;
|
return ResponseEntity.ok(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/loads")
|
@GetMapping("/loads")
|
||||||
@Operation(summary = "GET request count",
|
@Operation(summary = "GET request count",
|
||||||
description = "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.")
|
description = "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.")
|
||||||
public Double getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
public ResponseEntity<?> getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||||
try {
|
if (!metricsEnabled) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
|
||||||
double count = 0.0;
|
double count = 0.0;
|
||||||
|
|
||||||
@@ -68,36 +101,165 @@ public class MetricsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return ResponseEntity.ok(count);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return -1.0;
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/loads/all")
|
||||||
|
@Operation(summary = "GET requests count for all endpoints",
|
||||||
|
description = "This endpoint returns the count of GET requests for each endpoint.")
|
||||||
|
public ResponseEntity<?> getAllEndpointLoads() {
|
||||||
|
if (!metricsEnabled) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, Double> counts = new HashMap<>();
|
||||||
|
|
||||||
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
|
String method = meter.getId().getTag("method");
|
||||||
|
if (method != null && method.equals("GET")) {
|
||||||
|
String uri = meter.getId().getTag("uri");
|
||||||
|
if (uri != null) {
|
||||||
|
double currentCount = counts.getOrDefault(uri, 0.0);
|
||||||
|
if (meter instanceof Counter) {
|
||||||
|
currentCount += ((Counter) meter).count();
|
||||||
|
}
|
||||||
|
counts.put(uri, currentCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EndpointCount> results = counts.entrySet().stream()
|
||||||
|
.map(entry -> new EndpointCount(entry.getKey(), entry.getValue()))
|
||||||
|
.sorted(Comparator.comparing(EndpointCount::getCount).reversed())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(results);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EndpointCount {
|
||||||
|
private String endpoint;
|
||||||
|
private double count;
|
||||||
|
|
||||||
|
public EndpointCount(String endpoint, double count) {
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
public String getEndpoint() {
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
public void setEndpoint(String endpoint) {
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
}
|
||||||
|
public double getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
public void setCount(double count) {
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/requests")
|
@GetMapping("/requests")
|
||||||
@Operation(summary = "POST request count",
|
@Operation(summary = "POST request count",
|
||||||
description = "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.")
|
description = "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.")
|
||||||
public Double getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
public ResponseEntity<?> getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||||
try {
|
if (!metricsEnabled) {
|
||||||
Counter counter;
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
|
||||||
if(!endpoint.get().startsWith("/")) {
|
|
||||||
endpoint = Optional.of("/" + endpoint.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("loads " + endpoint.get() + " vs " + meterRegistry.get("http.requests").tags("uri", endpoint.get()).toString());
|
|
||||||
counter = meterRegistry.get("http.requests")
|
|
||||||
.tags("method", "POST", "uri", endpoint.get()).counter();
|
|
||||||
} else {
|
|
||||||
counter = meterRegistry.get("http.requests")
|
|
||||||
.tags("method", "POST").counter();
|
|
||||||
}
|
|
||||||
return counter.count();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return 0.0;
|
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
double count = 0.0;
|
||||||
|
|
||||||
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
|
String method = meter.getId().getTag("method");
|
||||||
|
if (method != null && method.equals("POST")) {
|
||||||
|
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
||||||
|
if (!endpoint.get().startsWith("/")) {
|
||||||
|
endpoint = Optional.of("/" + endpoint.get());
|
||||||
|
}
|
||||||
|
if (endpoint.get().equals(meter.getId().getTag("uri"))) {
|
||||||
|
if (meter instanceof Counter) {
|
||||||
|
count += ((Counter) meter).count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (meter instanceof Counter) {
|
||||||
|
count += ((Counter) meter).count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(count);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.ok(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/requests/all")
|
||||||
|
@Operation(summary = "POST requests count for all endpoints",
|
||||||
|
description = "This endpoint returns the count of POST requests for each endpoint.")
|
||||||
|
public ResponseEntity<?> getAllPostRequests() {
|
||||||
|
if (!metricsEnabled) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, Double> counts = new HashMap<>();
|
||||||
|
|
||||||
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
|
String method = meter.getId().getTag("method");
|
||||||
|
if (method != null && method.equals("POST")) {
|
||||||
|
String uri = meter.getId().getTag("uri");
|
||||||
|
if (uri != null) {
|
||||||
|
double currentCount = counts.getOrDefault(uri, 0.0);
|
||||||
|
if (meter instanceof Counter) {
|
||||||
|
currentCount += ((Counter) meter).count();
|
||||||
|
}
|
||||||
|
counts.put(uri, currentCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EndpointCount> results = counts.entrySet().stream()
|
||||||
|
.map(entry -> new EndpointCount(entry.getKey(), entry.getValue()))
|
||||||
|
.sorted(Comparator.comparing(EndpointCount::getCount).reversed())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(results);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/uptime")
|
||||||
|
public ResponseEntity<?> getUptime() {
|
||||||
|
if (!metricsEnabled) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
Duration uptime = Duration.between(StartupApplicationListener.startTime, now);
|
||||||
|
return ResponseEntity.ok(formatDuration(uptime));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatDuration(Duration duration) {
|
||||||
|
long days = duration.toDays();
|
||||||
|
long hours = duration.toHoursPart();
|
||||||
|
long minutes = duration.toMinutesPart();
|
||||||
|
long seconds = duration.toSecondsPart();
|
||||||
|
return String.format("%dd %dh %dm %ds", days, hours, minutes, seconds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,21 @@ public class OtherWebController {
|
|||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/show-javascript")
|
||||||
|
@Hidden
|
||||||
|
public String extractJavascriptForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "show-javascript");
|
||||||
|
return "other/show-javascript";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/add-page-numbers")
|
||||||
|
@Hidden
|
||||||
|
public String addPageNumbersForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "add-page-numbers");
|
||||||
|
return "other/add-page-numbers";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/extract-images")
|
@GetMapping("/extract-images")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String extractImagesForm(Model model) {
|
public String extractImagesForm(Model model) {
|
||||||
@@ -133,4 +148,13 @@ public class OtherWebController {
|
|||||||
return "other/auto-crop";
|
return "other/auto-crop";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/auto-rename")
|
||||||
|
@Hidden
|
||||||
|
public String autoRenameForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "auto-rename");
|
||||||
|
return "other/auto-rename";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
@Controller
|
@Controller
|
||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class SecurityWebController {
|
public class SecurityWebController {
|
||||||
|
|
||||||
|
@GetMapping("/auto-redact")
|
||||||
|
@Hidden
|
||||||
|
public String autoRedactForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "auto-redact");
|
||||||
|
return "security/auto-redact";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/add-password")
|
@GetMapping("/add-password")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String addPasswordForm(Model model) {
|
public String addPasswordForm(Model model) {
|
||||||
@@ -43,4 +51,18 @@ public class SecurityWebController {
|
|||||||
model.addAttribute("currentPage", "cert-sign");
|
model.addAttribute("currentPage", "cert-sign");
|
||||||
return "security/cert-sign";
|
return "security/cert-sign";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/sanitize-pdf")
|
||||||
|
@Hidden
|
||||||
|
public String sanitizeForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "sanitize-pdf");
|
||||||
|
return "security/sanitize-pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-info-on-pdf")
|
||||||
|
@Hidden
|
||||||
|
public String getInfo(Model model) {
|
||||||
|
model.addAttribute("currentPage", "get-info-on-pdf");
|
||||||
|
return "security/get-info-on-pdf";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
|
public class ApiKeyAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
|
||||||
|
private final Object principal;
|
||||||
|
private Object credentials;
|
||||||
|
|
||||||
|
public ApiKeyAuthenticationToken(String apiKey) {
|
||||||
|
super(null);
|
||||||
|
this.principal = null;
|
||||||
|
this.credentials = apiKey;
|
||||||
|
setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiKeyAuthenticationToken(Object principal, String apiKey, Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
super(authorities);
|
||||||
|
this.principal = principal; // principal can be a UserDetails object
|
||||||
|
this.credentials = apiKey;
|
||||||
|
super.setAuthenticated(true); // this authentication is trusted
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCredentials() {
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
||||||
|
if (isAuthenticated) {
|
||||||
|
throw new IllegalArgumentException("Cannot set this token to trusted. Use constructor which takes a GrantedAuthority list instead.");
|
||||||
|
}
|
||||||
|
super.setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eraseCredentials() {
|
||||||
|
super.eraseCredentials();
|
||||||
|
credentials = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,330 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.YamlPropertySourceFactory;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "")
|
||||||
|
@PropertySource(value = "file:./configs/settings.yml", factory = YamlPropertySourceFactory.class)
|
||||||
|
public class ApplicationProperties {
|
||||||
|
private Security security;
|
||||||
|
private System system;
|
||||||
|
private Ui ui;
|
||||||
|
private Endpoints endpoints;
|
||||||
|
private Metrics metrics;
|
||||||
|
private AutomaticallyGenerated automaticallyGenerated;
|
||||||
|
private AutoPipeline autoPipeline;
|
||||||
|
|
||||||
|
public AutoPipeline getAutoPipeline() {
|
||||||
|
return autoPipeline != null ? autoPipeline : new AutoPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoPipeline(AutoPipeline autoPipeline) {
|
||||||
|
this.autoPipeline = autoPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Security getSecurity() {
|
||||||
|
return security != null ? security : new Security();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecurity(Security security) {
|
||||||
|
this.security = security;
|
||||||
|
}
|
||||||
|
|
||||||
|
public System getSystem() {
|
||||||
|
return system != null ? system : new System();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSystem(System system) {
|
||||||
|
this.system = system;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ui getUi() {
|
||||||
|
return ui != null ? ui : new Ui();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUi(Ui ui) {
|
||||||
|
this.ui = ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Endpoints getEndpoints() {
|
||||||
|
return endpoints != null ? endpoints : new Endpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndpoints(Endpoints endpoints) {
|
||||||
|
this.endpoints = endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Metrics getMetrics() {
|
||||||
|
return metrics != null ? metrics : new Metrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetrics(Metrics metrics) {
|
||||||
|
this.metrics = metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutomaticallyGenerated getAutomaticallyGenerated() {
|
||||||
|
return automaticallyGenerated != null ? automaticallyGenerated : new AutomaticallyGenerated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutomaticallyGenerated(AutomaticallyGenerated automaticallyGenerated) {
|
||||||
|
this.automaticallyGenerated = automaticallyGenerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ApplicationProperties [security=" + security + ", system=" + system + ", ui=" + ui + ", endpoints="
|
||||||
|
+ endpoints + ", metrics=" + metrics + ", automaticallyGenerated=" + automaticallyGenerated
|
||||||
|
+ ", autoPipeline=" + autoPipeline + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AutoPipeline {
|
||||||
|
private String outputFolder;
|
||||||
|
|
||||||
|
public String getOutputFolder() {
|
||||||
|
return outputFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutputFolder(String outputFolder) {
|
||||||
|
this.outputFolder = outputFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AutoPipeline [outputFolder=" + outputFolder + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
public static class Security {
|
||||||
|
private Boolean enableLogin;
|
||||||
|
private InitialLogin initialLogin;
|
||||||
|
private Boolean csrfDisabled;
|
||||||
|
|
||||||
|
public Boolean getEnableLogin() {
|
||||||
|
return enableLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableLogin(Boolean enableLogin) {
|
||||||
|
this.enableLogin = enableLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InitialLogin getInitialLogin() {
|
||||||
|
return initialLogin != null ? initialLogin : new InitialLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitialLogin(InitialLogin initialLogin) {
|
||||||
|
this.initialLogin = initialLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getCsrfDisabled() {
|
||||||
|
return csrfDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCsrfDisabled(Boolean csrfDisabled) {
|
||||||
|
this.csrfDisabled = csrfDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Security [enableLogin=" + enableLogin + ", initialLogin=" + initialLogin + ", csrfDisabled="
|
||||||
|
+ csrfDisabled + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class InitialLogin {
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "InitialLogin [username=" + username + ", password=" + (password != null && !password.isEmpty() ? "MASKED" : "NULL") + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class System {
|
||||||
|
private String defaultLocale;
|
||||||
|
private Boolean googlevisibility;
|
||||||
|
private String rootURIPath;
|
||||||
|
private String customStaticFilePath;
|
||||||
|
private Integer maxFileSize;
|
||||||
|
|
||||||
|
public String getDefaultLocale() {
|
||||||
|
return defaultLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultLocale(String defaultLocale) {
|
||||||
|
this.defaultLocale = defaultLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getGooglevisibility() {
|
||||||
|
return googlevisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGooglevisibility(Boolean googlevisibility) {
|
||||||
|
this.googlevisibility = googlevisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRootURIPath() {
|
||||||
|
return rootURIPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRootURIPath(String rootURIPath) {
|
||||||
|
this.rootURIPath = rootURIPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomStaticFilePath() {
|
||||||
|
return customStaticFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomStaticFilePath(String customStaticFilePath) {
|
||||||
|
this.customStaticFilePath = customStaticFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxFileSize() {
|
||||||
|
return maxFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxFileSize(Integer maxFileSize) {
|
||||||
|
this.maxFileSize = maxFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "System [defaultLocale=" + defaultLocale + ", googlevisibility=" + googlevisibility + ", rootURIPath="
|
||||||
|
+ rootURIPath + ", customStaticFilePath=" + customStaticFilePath + ", maxFileSize=" + maxFileSize
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ui {
|
||||||
|
private String appName;
|
||||||
|
private String homeDescription;
|
||||||
|
private String appNameNavbar;
|
||||||
|
|
||||||
|
public String getAppName() {
|
||||||
|
return appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppName(String appName) {
|
||||||
|
this.appName = appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHomeDescription() {
|
||||||
|
return homeDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHomeDescription(String homeDescription) {
|
||||||
|
this.homeDescription = homeDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAppNameNavbar() {
|
||||||
|
return appNameNavbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppNameNavbar(String appNameNavbar) {
|
||||||
|
this.appNameNavbar = appNameNavbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UserInterface [appName=" + appName + ", homeDescription=" + homeDescription + ", appNameNavbar=" + appNameNavbar + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Endpoints {
|
||||||
|
private List<String> toRemove;
|
||||||
|
private List<String> groupsToRemove;
|
||||||
|
|
||||||
|
public List<String> getToRemove() {
|
||||||
|
return toRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToRemove(List<String> toRemove) {
|
||||||
|
this.toRemove = toRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getGroupsToRemove() {
|
||||||
|
return groupsToRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupsToRemove(List<String> groupsToRemove) {
|
||||||
|
this.groupsToRemove = groupsToRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Endpoints [toRemove=" + toRemove + ", groupsToRemove=" + groupsToRemove + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Metrics {
|
||||||
|
private Boolean enabled;
|
||||||
|
|
||||||
|
public Boolean getEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(Boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Metrics [enabled=" + enabled + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AutomaticallyGenerated {
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AutomaticallyGenerated [key=" + (key != null && !key.isEmpty() ? "MASKED" : "NULL") + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/main/java/stirling/software/SPDF/model/Authority.java
Normal file
64
src/main/java/stirling/software/SPDF/model/Authority.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "authorities")
|
||||||
|
public class Authority {
|
||||||
|
|
||||||
|
public Authority() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Authority(String authority, User user) {
|
||||||
|
this.authority = authority;
|
||||||
|
this.user = user;
|
||||||
|
user.getAuthorities().add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "authority")
|
||||||
|
private String authority;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthority() {
|
||||||
|
return authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthority(String authority) {
|
||||||
|
this.authority = authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
42
src/main/java/stirling/software/SPDF/model/PDFText.java
Normal file
42
src/main/java/stirling/software/SPDF/model/PDFText.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
public class PDFText {
|
||||||
|
private final int pageIndex;
|
||||||
|
private final float x1;
|
||||||
|
private final float y1;
|
||||||
|
private final float x2;
|
||||||
|
private final float y2;
|
||||||
|
private final String text;
|
||||||
|
|
||||||
|
public PDFText(int pageIndex, float x1, float y1, float x2, float y2, String text) {
|
||||||
|
this.pageIndex = pageIndex;
|
||||||
|
this.x1 = x1;
|
||||||
|
this.y1 = y1;
|
||||||
|
this.x2 = x2;
|
||||||
|
this.y2 = y2;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPageIndex() {
|
||||||
|
return pageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getX1() {
|
||||||
|
return x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getY1() {
|
||||||
|
return y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getX2() {
|
||||||
|
return x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getY2() {
|
||||||
|
return y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "persistent_logins")
|
||||||
|
public class PersistentLogin {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "series")
|
||||||
|
private String series;
|
||||||
|
|
||||||
|
@Column(name = "username", length = 64, nullable = false)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(name = "token", length = 64, nullable = false)
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
@Column(name = "last_used", nullable = false)
|
||||||
|
private Date lastUsed;
|
||||||
|
|
||||||
|
public String getSeries() {
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeries(String series) {
|
||||||
|
this.series = series;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLastUsed() {
|
||||||
|
return lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUsed(Date lastUsed) {
|
||||||
|
this.lastUsed = lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Getters, setters, etc.
|
||||||
|
}
|
||||||
@@ -22,4 +22,11 @@ public class PipelineOperation {
|
|||||||
public void setParameters(Map<String, Object> parameters) {
|
public void setParameters(Map<String, Object> parameters) {
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PipelineOperation [operation=" + operation + ", parameters=" + parameters + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
50
src/main/java/stirling/software/SPDF/model/Role.java
Normal file
50
src/main/java/stirling/software/SPDF/model/Role.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
public enum Role {
|
||||||
|
|
||||||
|
// Unlimited access
|
||||||
|
ADMIN("ROLE_ADMIN", Integer.MAX_VALUE, Integer.MAX_VALUE),
|
||||||
|
|
||||||
|
// Unlimited access
|
||||||
|
USER("ROLE_USER", Integer.MAX_VALUE, Integer.MAX_VALUE),
|
||||||
|
|
||||||
|
// 40 API calls Per Day, 40 web calls
|
||||||
|
LIMITED_API_USER("ROLE_LIMITED_API_USER", 40, 40),
|
||||||
|
|
||||||
|
// 20 API calls Per Day, 20 web calls
|
||||||
|
EXTRA_LIMITED_API_USER("ROLE_EXTRA_LIMITED_API_USER", 20, 20),
|
||||||
|
|
||||||
|
// 0 API calls per day and 20 web calls
|
||||||
|
WEB_ONLY_USER("ROLE_WEB_ONLY_USER", 0, 20);
|
||||||
|
|
||||||
|
private final String roleId;
|
||||||
|
private final int apiCallsPerDay;
|
||||||
|
private final int webCallsPerDay;
|
||||||
|
|
||||||
|
Role(String roleId, int apiCallsPerDay, int webCallsPerDay) {
|
||||||
|
this.roleId = roleId;
|
||||||
|
this.apiCallsPerDay = apiCallsPerDay;
|
||||||
|
this.webCallsPerDay = webCallsPerDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleId() {
|
||||||
|
return roleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getApiCallsPerDay() {
|
||||||
|
return apiCallsPerDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWebCallsPerDay() {
|
||||||
|
return webCallsPerDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Role fromString(String roleId) {
|
||||||
|
for (Role role : Role.values()) {
|
||||||
|
if (role.getRoleId().equalsIgnoreCase(roleId)) {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("No Role defined for id: " + roleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
124
src/main/java/stirling/software/SPDF/model/User.java
Normal file
124
src/main/java/stirling/software/SPDF/model/User.java
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.CollectionTable;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.MapKeyColumn;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "user_id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "username", unique = true)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(name = "password")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(name = "apiKey")
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
@Column(name = "enabled")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user")
|
||||||
|
private Set<Authority> authorities = new HashSet<>();
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@MapKeyColumn(name = "setting_key")
|
||||||
|
@Column(name = "setting_value")
|
||||||
|
@CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id"))
|
||||||
|
private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiKey() {
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiKey(String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getSettings() {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSettings(Map<String, String> settings) {
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Authority> getAuthorities() {
|
||||||
|
return authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthorities(Set<Authority> authorities) {
|
||||||
|
this.authorities = authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAuthorities(Set<Authority> authorities) {
|
||||||
|
this.authorities.addAll(authorities);
|
||||||
|
}
|
||||||
|
public void addAuthority(Authority authorities) {
|
||||||
|
this.authorities.add(authorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRolesAsString() {
|
||||||
|
return this.authorities.stream()
|
||||||
|
.map(Authority::getAuthority)
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
90
src/main/java/stirling/software/SPDF/pdf/TextFinder.java
Normal file
90
src/main/java/stirling/software/SPDF/pdf/TextFinder.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package stirling.software.SPDF.pdf;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
|
import org.apache.pdfbox.text.TextPosition;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.PDFText;
|
||||||
|
|
||||||
|
public class TextFinder extends PDFTextStripper {
|
||||||
|
|
||||||
|
private final String searchText;
|
||||||
|
private final boolean useRegex;
|
||||||
|
private final boolean wholeWordSearch;
|
||||||
|
private final List<PDFText> textOccurrences = new ArrayList<>();
|
||||||
|
|
||||||
|
public TextFinder(String searchText, boolean useRegex, boolean wholeWordSearch) throws IOException {
|
||||||
|
this.searchText = searchText.toLowerCase();
|
||||||
|
this.useRegex = useRegex;
|
||||||
|
this.wholeWordSearch = wholeWordSearch;
|
||||||
|
setSortByPosition(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> findOccurrencesInText(String searchText, String content) {
|
||||||
|
List<Integer> indexes = new ArrayList<>();
|
||||||
|
Pattern pattern;
|
||||||
|
|
||||||
|
if (useRegex) {
|
||||||
|
// Use regex-based search
|
||||||
|
pattern = wholeWordSearch
|
||||||
|
? Pattern.compile("(\\b|_|\\.)" + searchText + "(\\b|_|\\.)")
|
||||||
|
: Pattern.compile(searchText);
|
||||||
|
} else {
|
||||||
|
// Use normal text search
|
||||||
|
pattern = wholeWordSearch
|
||||||
|
? Pattern.compile("(\\b|_|\\.)" + Pattern.quote(searchText) + "(\\b|_|\\.)")
|
||||||
|
: Pattern.compile(Pattern.quote(searchText));
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = pattern.matcher(content);
|
||||||
|
while (matcher.find()) {
|
||||||
|
indexes.add(matcher.start());
|
||||||
|
}
|
||||||
|
return indexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeString(String text, List<TextPosition> textPositions) {
|
||||||
|
for (Integer index : findOccurrencesInText(searchText, text.toLowerCase())) {
|
||||||
|
if (index + searchText.length() <= textPositions.size()) {
|
||||||
|
// Initial values based on the first character
|
||||||
|
TextPosition first = textPositions.get(index);
|
||||||
|
float minX = first.getX();
|
||||||
|
float minY = first.getY();
|
||||||
|
float maxX = first.getX() + first.getWidth();
|
||||||
|
float maxY = first.getY() + first.getHeight();
|
||||||
|
|
||||||
|
// Loop over the rest of the characters and adjust bounding box values
|
||||||
|
for (int i = index; i < index + searchText.length(); i++) {
|
||||||
|
TextPosition position = textPositions.get(i);
|
||||||
|
minX = Math.min(minX, position.getX());
|
||||||
|
minY = Math.min(minY, position.getY());
|
||||||
|
maxX = Math.max(maxX, position.getX() + position.getWidth());
|
||||||
|
maxY = Math.max(maxY, position.getY() + position.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
textOccurrences.add(new PDFText(
|
||||||
|
getCurrentPageNo() - 1,
|
||||||
|
minX,
|
||||||
|
minY,
|
||||||
|
maxX,
|
||||||
|
maxY,
|
||||||
|
text
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PDFText> getTextLocations(PDDocument document) throws Exception {
|
||||||
|
this.getText(document);
|
||||||
|
System.out.println("Found " + textOccurrences.size() + " occurrences of '" + searchText + "' in the document.");
|
||||||
|
|
||||||
|
return textOccurrences;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.Authority;
|
||||||
|
|
||||||
|
public interface AuthorityRepository extends JpaRepository<Authority, Long> {
|
||||||
|
//Set<Authority> findByUsername(String username);
|
||||||
|
Set<Authority> findByUser_Username(String username);
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.PersistentLogin;
|
||||||
|
|
||||||
|
public class JPATokenRepositoryImpl implements PersistentTokenRepository {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PersistentLoginRepository persistentLoginRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createNewToken(PersistentRememberMeToken token) {
|
||||||
|
PersistentLogin newToken = new PersistentLogin();
|
||||||
|
newToken.setSeries(token.getSeries());
|
||||||
|
newToken.setUsername(token.getUsername());
|
||||||
|
newToken.setToken(token.getTokenValue());
|
||||||
|
newToken.setLastUsed(token.getDate());
|
||||||
|
persistentLoginRepository.save(newToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateToken(String series, String tokenValue, Date lastUsed) {
|
||||||
|
PersistentLogin existingToken = persistentLoginRepository.findById(series).orElse(null);
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingToken.setToken(tokenValue);
|
||||||
|
existingToken.setLastUsed(lastUsed);
|
||||||
|
persistentLoginRepository.save(existingToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistentRememberMeToken getTokenForSeries(String seriesId) {
|
||||||
|
PersistentLogin token = persistentLoginRepository.findById(seriesId).orElse(null);
|
||||||
|
if (token != null) {
|
||||||
|
return new PersistentRememberMeToken(token.getUsername(), token.getSeries(), token.getToken(), token.getLastUsed());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUserTokens(String username) {
|
||||||
|
for (PersistentLogin token : persistentLoginRepository.findAll()) {
|
||||||
|
if (token.getUsername().equals(username)) {
|
||||||
|
persistentLoginRepository.delete(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.PersistentLogin;
|
||||||
|
|
||||||
|
public interface PersistentLoginRepository extends JpaRepository<PersistentLogin, String> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.User;
|
||||||
|
|
||||||
|
public interface UserRepository extends JpaRepository<User, String> {
|
||||||
|
Optional<User> findByUsername(String username);
|
||||||
|
User findByApiKey(String apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
95
src/main/java/stirling/software/SPDF/utils/FileToPdf.java
Normal file
95
src/main/java/stirling/software/SPDF/utils/FileToPdf.java
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
|
||||||
|
public class FileToPdf {
|
||||||
|
public static byte[] convertHtmlToPdf(byte[] fileBytes, String fileName) throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
|
Path tempInputFile = null;
|
||||||
|
byte[] pdfBytes;
|
||||||
|
try {
|
||||||
|
if (fileName.endsWith(".html")) {
|
||||||
|
tempInputFile = Files.createTempFile("input_", ".html");
|
||||||
|
Files.write(tempInputFile, fileBytes);
|
||||||
|
} else {
|
||||||
|
tempInputFile = unzipAndGetMainHtml(fileBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> command = new ArrayList<>();
|
||||||
|
command.add("weasyprint");
|
||||||
|
command.add(tempInputFile.toString());
|
||||||
|
command.add(tempOutputFile.toString());
|
||||||
|
ProcessExecutorResult returnCode;
|
||||||
|
if (fileName.endsWith(".zip")) {
|
||||||
|
returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
|
||||||
|
.runCommandWithOutputHandling(command, tempInputFile.getParent().toFile());
|
||||||
|
} else {
|
||||||
|
|
||||||
|
returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
|
||||||
|
.runCommandWithOutputHandling(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
} finally {
|
||||||
|
// Clean up temporary files
|
||||||
|
Files.delete(tempOutputFile);
|
||||||
|
Files.delete(tempInputFile);
|
||||||
|
|
||||||
|
if (fileName.endsWith(".zip")) {
|
||||||
|
GeneralUtils.deleteDirectory(tempInputFile.getParent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdfBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException {
|
||||||
|
Path tempDirectory = Files.createTempDirectory("unzipped_");
|
||||||
|
try (ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(fileBytes))) {
|
||||||
|
ZipEntry entry = zipIn.getNextEntry();
|
||||||
|
while (entry != null) {
|
||||||
|
Path filePath = tempDirectory.resolve(entry.getName());
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
Files.createDirectories(filePath); // Explicitly create the directory structure
|
||||||
|
} else {
|
||||||
|
Files.createDirectories(filePath.getParent()); // Create parent directories if they don't exist
|
||||||
|
Files.copy(zipIn, filePath);
|
||||||
|
}
|
||||||
|
zipIn.closeEntry();
|
||||||
|
entry = zipIn.getNextEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//search for the main HTML file.
|
||||||
|
try (Stream<Path> walk = Files.walk(tempDirectory)) {
|
||||||
|
List<Path> htmlFiles = walk.filter(file -> file.toString().endsWith(".html"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (htmlFiles.isEmpty()) {
|
||||||
|
throw new IOException("No HTML files found in the unzipped directory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prioritize 'index.html' if it exists, otherwise use the first .html file
|
||||||
|
for (Path htmlFile : htmlFiles) {
|
||||||
|
if (htmlFile.getFileName().toString().equals("index.html")) {
|
||||||
|
return htmlFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlFiles.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,54 @@
|
|||||||
package stirling.software.SPDF.utils;
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GeneralUtils {
|
public class GeneralUtils {
|
||||||
|
|
||||||
|
public static void deleteDirectory(Path path) throws IOException {
|
||||||
|
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
Files.delete(file);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||||
|
Files.delete(dir);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertToFileName(String name) {
|
||||||
|
String safeName = name.replaceAll("[^a-zA-Z0-9]", "_");
|
||||||
|
if (safeName.length() > 50) {
|
||||||
|
safeName = safeName.substring(0, 50);
|
||||||
|
}
|
||||||
|
return safeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isValidURL(String urlStr) {
|
||||||
|
try {
|
||||||
|
new URL(urlStr);
|
||||||
|
return true;
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Long convertSizeToBytes(String sizeStr) {
|
public static Long convertSizeToBytes(String sizeStr) {
|
||||||
if (sizeStr == null) {
|
if (sizeStr == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -35,8 +79,14 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
// loop through the page order array
|
// loop through the page order array
|
||||||
for (String element : pageOrderArr) {
|
for (String element : pageOrderArr) {
|
||||||
// check if the element contains a range of pages
|
if (element.equalsIgnoreCase("all")) {
|
||||||
if (element.matches("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
|
for (int i = 0; i < totalPages; i++) {
|
||||||
|
newPageOrder.add(i);
|
||||||
|
}
|
||||||
|
// As all pages are already added, no need to check further
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (element.matches("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
|
||||||
// Handle page order as a function
|
// Handle page order as a function
|
||||||
int coefficient = 0;
|
int coefficient = 0;
|
||||||
int constant = 0;
|
int constant = 0;
|
||||||
@@ -88,4 +138,16 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
return newPageOrder;
|
return newPageOrder;
|
||||||
}
|
}
|
||||||
|
public static boolean createDir(String path) {
|
||||||
|
Path folder = Paths.get(path);
|
||||||
|
if (!Files.exists(folder)) {
|
||||||
|
try {
|
||||||
|
Files.createDirectories(folder);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import org.springframework.http.MediaType;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
|
||||||
public class PDFToFile {
|
public class PDFToFile {
|
||||||
public ResponseEntity<byte[]> processPdfToOfficeFormat(MultipartFile inputFile, String outputFormat, String libreOfficeFilter) throws IOException, InterruptedException {
|
public ResponseEntity<byte[]> processPdfToOfficeFormat(MultipartFile inputFile, String outputFormat, String libreOfficeFilter) throws IOException, InterruptedException {
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ public class PDFToFile {
|
|||||||
// Run the LibreOffice command
|
// Run the LibreOffice command
|
||||||
List<String> command = new ArrayList<>(
|
List<String> command = new ArrayList<>(
|
||||||
Arrays.asList("soffice", "--infilter=" + libreOfficeFilter, "--convert-to", outputFormat, "--outdir", tempOutputDir.toString(), tempInputFile.toString()));
|
Arrays.asList("soffice", "--infilter=" + libreOfficeFilter, "--convert-to", outputFormat, "--outdir", tempOutputDir.toString(), tempInputFile.toString()));
|
||||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command);
|
ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE).runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
// Get output files
|
// Get output files
|
||||||
List<File> outputFiles = Arrays.asList(tempOutputDir.toFile().listFiles());
|
List<File> outputFiles = Arrays.asList(tempOutputDir.toFile().listFiles());
|
||||||
|
|||||||
@@ -32,10 +32,6 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.itextpdf.kernel.pdf.PdfPage;
|
|
||||||
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
|
|
||||||
import com.itextpdf.kernel.pdf.canvas.parser.listener.SimpleTextExtractionStrategy;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.pdf.ImageFinder;
|
import stirling.software.SPDF.pdf.ImageFinder;
|
||||||
|
|
||||||
public class PdfUtils {
|
public class PdfUtils {
|
||||||
@@ -44,7 +40,7 @@ public class PdfUtils {
|
|||||||
|
|
||||||
|
|
||||||
public static PDRectangle textToPageSize(String size) {
|
public static PDRectangle textToPageSize(String size) {
|
||||||
switch (size) {
|
switch (size.toUpperCase()) {
|
||||||
case "A0":
|
case "A0":
|
||||||
return PDRectangle.A0;
|
return PDRectangle.A0;
|
||||||
case "A1":
|
case "A1":
|
||||||
@@ -68,44 +64,38 @@ public class PdfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasImageInFile(PDDocument pdfDocument, String text, String pagesToCheck) throws IOException {
|
|
||||||
PDFTextStripper textStripper = new PDFTextStripper();
|
|
||||||
String pdfText = "";
|
|
||||||
|
|
||||||
if(pagesToCheck == null || pagesToCheck.equals("all")) {
|
|
||||||
pdfText = textStripper.getText(pdfDocument);
|
|
||||||
} else {
|
|
||||||
// remove whitespaces
|
|
||||||
pagesToCheck = pagesToCheck.replaceAll("\\s+", "");
|
|
||||||
|
|
||||||
String[] splitPoints = pagesToCheck.split(",");
|
|
||||||
for (String splitPoint : splitPoints) {
|
|
||||||
if (splitPoint.contains("-")) {
|
|
||||||
// Handle page ranges
|
|
||||||
String[] range = splitPoint.split("-");
|
|
||||||
int startPage = Integer.parseInt(range[0]);
|
|
||||||
int endPage = Integer.parseInt(range[1]);
|
|
||||||
|
|
||||||
for (int i = startPage; i <= endPage; i++) {
|
public static boolean hasImages(PDDocument document, String pagesToCheck) throws IOException {
|
||||||
textStripper.setStartPage(i);
|
String[] pageOrderArr = pagesToCheck.split(",");
|
||||||
textStripper.setEndPage(i);
|
List<Integer> pageList = GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages());
|
||||||
pdfText += textStripper.getText(pdfDocument);
|
|
||||||
}
|
for (int pageNumber : pageList) {
|
||||||
} else {
|
PDPage page = document.getPage(pageNumber);
|
||||||
// Handle individual page
|
if (hasImagesOnPage(page)) {
|
||||||
int page = Integer.parseInt(splitPoint);
|
return true;
|
||||||
textStripper.setStartPage(page);
|
|
||||||
textStripper.setEndPage(page);
|
|
||||||
pdfText += textStripper.getText(pdfDocument);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfDocument.close();
|
return false;
|
||||||
|
|
||||||
return pdfText.contains(text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasText(PDDocument document, String pageNumbersToCheck, String phrase) throws IOException {
|
||||||
|
String[] pageOrderArr = pageNumbersToCheck.split(",");
|
||||||
|
List<Integer> pageList = GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages());
|
||||||
|
|
||||||
|
for (int pageNumber : pageList) {
|
||||||
|
PDPage page = document.getPage(pageNumber);
|
||||||
|
if (hasTextOnPage(page, phrase)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean hasImagesOnPage(PDPage page) throws IOException {
|
public static boolean hasImagesOnPage(PDPage page) throws IOException {
|
||||||
ImageFinder imageFinder = new ImageFinder(page);
|
ImageFinder imageFinder = new ImageFinder(page);
|
||||||
imageFinder.processPage(page);
|
imageFinder.processPage(page);
|
||||||
@@ -113,11 +103,16 @@ public class PdfUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean hasText(PDDocument document, String phrase) throws IOException {
|
|
||||||
PDFTextStripper pdfStripper = new PDFTextStripper();
|
|
||||||
String text = pdfStripper.getText(document);
|
public static boolean hasTextOnPage(PDPage page, String phrase) throws IOException {
|
||||||
return text.contains(phrase);
|
PDFTextStripper textStripper = new PDFTextStripper();
|
||||||
}
|
PDDocument tempDoc = new PDDocument();
|
||||||
|
tempDoc.addPage(page);
|
||||||
|
String pageText = textStripper.getText(tempDoc);
|
||||||
|
tempDoc.close();
|
||||||
|
return pageText.contains(phrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean containsTextInFile(PDDocument pdfDocument, String text, String pagesToCheck) throws IOException {
|
public boolean containsTextInFile(PDDocument pdfDocument, String text, String pagesToCheck) throws IOException {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package stirling.software.SPDF.utils;
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -13,7 +14,7 @@ import java.util.concurrent.Semaphore;
|
|||||||
public class ProcessExecutor {
|
public class ProcessExecutor {
|
||||||
|
|
||||||
public enum Processes {
|
public enum Processes {
|
||||||
LIBRE_OFFICE, OCR_MY_PDF, PYTHON_OPENCV, GHOSTSCRIPT
|
LIBRE_OFFICE, OCR_MY_PDF, PYTHON_OPENCV, GHOSTSCRIPT, WEASYPRINT
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<Processes, ProcessExecutor> instances = new ConcurrentHashMap<>();
|
private static final Map<Processes, ProcessExecutor> instances = new ConcurrentHashMap<>();
|
||||||
@@ -25,6 +26,7 @@ public class ProcessExecutor {
|
|||||||
case OCR_MY_PDF -> 2;
|
case OCR_MY_PDF -> 2;
|
||||||
case PYTHON_OPENCV -> 8;
|
case PYTHON_OPENCV -> 8;
|
||||||
case GHOSTSCRIPT -> 16;
|
case GHOSTSCRIPT -> 16;
|
||||||
|
case WEASYPRINT -> 16;
|
||||||
};
|
};
|
||||||
return new ProcessExecutor(semaphoreLimit);
|
return new ProcessExecutor(semaphoreLimit);
|
||||||
});
|
});
|
||||||
@@ -35,14 +37,22 @@ public class ProcessExecutor {
|
|||||||
private ProcessExecutor(int semaphoreLimit) {
|
private ProcessExecutor(int semaphoreLimit) {
|
||||||
this.semaphore = new Semaphore(semaphoreLimit);
|
this.semaphore = new Semaphore(semaphoreLimit);
|
||||||
}
|
}
|
||||||
|
public ProcessExecutorResult runCommandWithOutputHandling(List<String> command) throws IOException, InterruptedException {
|
||||||
public int runCommandWithOutputHandling(List<String> command) throws IOException, InterruptedException {
|
return runCommandWithOutputHandling(command, null);
|
||||||
|
}
|
||||||
|
public ProcessExecutorResult runCommandWithOutputHandling(List<String> command, File workingDirectory) throws IOException, InterruptedException {
|
||||||
int exitCode = 1;
|
int exitCode = 1;
|
||||||
|
String messages = "";
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
System.out.print("Running command: " + String.join(" ", command));
|
System.out.print("Running command: " + String.join(" ", command));
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||||
|
|
||||||
|
// Use the working directory if it's set
|
||||||
|
if (workingDirectory != null) {
|
||||||
|
processBuilder.directory(workingDirectory);
|
||||||
|
}
|
||||||
Process process = processBuilder.start();
|
Process process = processBuilder.start();
|
||||||
|
|
||||||
// Read the error stream and standard output stream concurrently
|
// Read the error stream and standard output stream concurrently
|
||||||
@@ -83,11 +93,13 @@ public class ProcessExecutor {
|
|||||||
|
|
||||||
if (outputLines.size() > 0) {
|
if (outputLines.size() > 0) {
|
||||||
String outputMessage = String.join("\n", outputLines);
|
String outputMessage = String.join("\n", outputLines);
|
||||||
|
messages += outputMessage;
|
||||||
System.out.println("Command output:\n" + outputMessage);
|
System.out.println("Command output:\n" + outputMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorLines.size() > 0) {
|
if (errorLines.size() > 0) {
|
||||||
String errorMessage = String.join("\n", errorLines);
|
String errorMessage = String.join("\n", errorLines);
|
||||||
|
messages += errorMessage;
|
||||||
System.out.println("Command error output:\n" + errorMessage);
|
System.out.println("Command error output:\n" + errorMessage);
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
throw new IOException("Command process failed with exit code " + exitCode + ". Error message: " + errorMessage);
|
throw new IOException("Command process failed with exit code " + exitCode + ". Error message: " + errorMessage);
|
||||||
@@ -96,7 +108,28 @@ public class ProcessExecutor {
|
|||||||
} finally {
|
} finally {
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
}
|
}
|
||||||
return exitCode;
|
return new ProcessExecutorResult(exitCode, messages);
|
||||||
}
|
}
|
||||||
|
public class ProcessExecutorResult{
|
||||||
|
int rc;
|
||||||
|
String messages;
|
||||||
|
public ProcessExecutorResult(int rc, String messages) {
|
||||||
|
this.rc = rc;
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
public int getRc() {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
public void setRc(int rc) {
|
||||||
|
this.rc = rc;
|
||||||
|
}
|
||||||
|
public String getMessages() {
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
public void setMessages(String messages) {
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PropertyConfigs {
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean getBooleanValue(List<String> keys, boolean defaultValue) {
|
||||||
|
for (String key : keys) {
|
||||||
|
String value = System.getProperty(key);
|
||||||
|
if (value == null)
|
||||||
|
value = System.getenv(key);
|
||||||
|
|
||||||
|
if (value != null)
|
||||||
|
return Boolean.valueOf(value);
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStringValue(List<String> keys, String defaultValue) {
|
||||||
|
for (String key : keys) {
|
||||||
|
String value = System.getProperty(key);
|
||||||
|
if (value == null)
|
||||||
|
value = System.getenv(key);
|
||||||
|
|
||||||
|
if (value != null)
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean getBooleanValue(String key, boolean defaultValue) {
|
||||||
|
String value = System.getProperty(key);
|
||||||
|
if (value == null)
|
||||||
|
value = System.getenv(key);
|
||||||
|
return (value != null) ? Boolean.valueOf(value) : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStringValue(String key, String defaultValue) {
|
||||||
|
String value = System.getProperty(key);
|
||||||
|
if (value == null)
|
||||||
|
value = System.getenv(key);
|
||||||
|
return (value != null) ? value : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,6 +10,10 @@ import org.springframework.http.HttpHeaders;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||||
|
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||||
|
|
||||||
public class WebResponseUtils {
|
public class WebResponseUtils {
|
||||||
|
|
||||||
@@ -21,6 +25,16 @@ public class WebResponseUtils {
|
|||||||
return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType);
|
return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ResponseEntity<byte[]> multiPartFileToWebResponse(MultipartFile file) throws IOException {
|
||||||
|
String fileName = file.getOriginalFilename();
|
||||||
|
MediaType mediaType = MediaType.parseMediaType(file.getContentType());
|
||||||
|
|
||||||
|
byte[] bytes = file.getBytes();
|
||||||
|
|
||||||
|
return bytesToWebResponse(bytes, fileName, mediaType);
|
||||||
|
}
|
||||||
|
|
||||||
public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType) throws IOException {
|
public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType) throws IOException {
|
||||||
|
|
||||||
// Return the PDF as a response
|
// Return the PDF as a response
|
||||||
@@ -47,4 +61,18 @@ public class WebResponseUtils {
|
|||||||
return boasToWebResponse(baos, docName);
|
return boasToWebResponse(baos, docName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ResponseEntity<byte[]> pdfDocToWebResponse(PdfDocument document, String docName) throws IOException {
|
||||||
|
|
||||||
|
// Open Byte Array and save document to it
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
PdfWriter writer = new PdfWriter(baos);
|
||||||
|
PdfDocument newDocument = new PdfDocument(writer);
|
||||||
|
|
||||||
|
document.copyPagesTo(1, document.getNumberOfPages(), newDocument);
|
||||||
|
newDocument.close();
|
||||||
|
|
||||||
|
return boasToWebResponse(baos, docName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,30 @@ server.error.include-stacktrace=always
|
|||||||
server.error.include-exception=true
|
server.error.include-exception=true
|
||||||
server.error.include-message=always
|
server.error.include-message=always
|
||||||
|
|
||||||
|
#logging.level.org.springframework.web=DEBUG
|
||||||
|
#logging.level.org.springframework=DEBUG
|
||||||
|
#logging.level.org.springframework.security=DEBUG
|
||||||
|
|
||||||
|
|
||||||
server.servlet.session.tracking-modes=cookie
|
server.servlet.session.tracking-modes=cookie
|
||||||
server.servlet.context-path=${APP_ROOT_PATH:/}
|
server.servlet.context-path=${SYSTEM_ROOTURIPATH:/}
|
||||||
|
|
||||||
spring.devtools.restart.enabled=true
|
spring.devtools.restart.enabled=true
|
||||||
spring.devtools.livereload.enabled=true
|
spring.devtools.livereload.enabled=true
|
||||||
|
|
||||||
spring.thymeleaf.encoding=UTF-8
|
spring.thymeleaf.encoding=UTF-8
|
||||||
|
|
||||||
server.connection-timeout=${CONNECTION_TIMEOUT:5m}
|
server.connection-timeout=${SYSTEM_CONNECTIONTIMEOUTMINUTES:5m}
|
||||||
spring.mvc.async.request-timeout=${ASYNC_CONNECTION_TIMEOUT:300000}
|
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:300000}
|
||||||
|
|
||||||
|
spring.resources.static-locations=file:customFiles/static/
|
||||||
|
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
|
||||||
|
#spring.thymeleaf.cache=false
|
||||||
|
|
||||||
|
|
||||||
|
spring.datasource.url=jdbc:h2:file:./configs/stirling-pdf-DB;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||||
|
spring.datasource.driver-class-name=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=
|
||||||
|
spring.h2.console.enabled=true
|
||||||
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#
|
|
||||||
# Translated by Google Translate #
|
|
||||||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#
|
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr=left to right, rtl=right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=rtl
|
language.direction=rtl
|
||||||
|
|
||||||
pdfPrompt=اختر PDF
|
pdfPrompt=اختر PDF
|
||||||
@@ -21,190 +17,509 @@ false=\u062E\u0637\u0623
|
|||||||
unknown=\u063A\u064A\u0631 \u0645\u0639\u0631\u0648\u0641
|
unknown=\u063A\u064A\u0631 \u0645\u0639\u0631\u0648\u0641
|
||||||
save=\u062D\u0641\u0638
|
save=\u062D\u0641\u0638
|
||||||
close=\u0625\u063A\u0644\u0627\u0642
|
close=\u0625\u063A\u0644\u0627\u0642
|
||||||
filesSelected = الملفات المحددة
|
filesSelected=الملفات المحددة
|
||||||
noFavourites = لم تتم إضافة أي مفضلات
|
noFavourites=لم تتم إضافة أي مفضلات
|
||||||
bored = الانتظار بالملل؟
|
bored=الانتظار بالملل؟
|
||||||
alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629
|
alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629
|
||||||
#############
|
downloadPdf=تنزيل PDF
|
||||||
# HOME-PAGE #
|
text=نص
|
||||||
#############
|
font=الخط
|
||||||
home.desc=متجرك الشامل المستضاف محليًا لجميع احتياجات PDF الخاصة بك.
|
selectFillter=- حدد -
|
||||||
|
pageNum=رقم الصفحة
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
navbar.convert=تحويل
|
navbar.convert=تحويل
|
||||||
navbar.security=الأمان
|
navbar.security=الأمان
|
||||||
navbar.other=أخرى
|
navbar.other=أخرى
|
||||||
navbar.darkmode=الوضع الداكن
|
navbar.darkmode=الوضع الداكن
|
||||||
navbar.pageOps=عمليات الصفحة
|
navbar.pageOps=عمليات الصفحة
|
||||||
|
navbar.settings=\u0625\u0639\u062F\u0627\u062F\u0627\u062A
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=\u0627\u0644\u0625\u0639\u062F\u0627\u062F\u0627\u062A
|
||||||
|
settings.update=\u0627\u0644\u062A\u062D\u062F\u064A\u062B \u0645\u062A\u0627\u062D
|
||||||
|
settings.appVersion=\u0625\u0635\u062F\u0627\u0631 \u0627\u0644\u062A\u0637\u0628\u064A\u0642:
|
||||||
|
settings.downloadOption.title=\u062A\u062D\u062F\u064A\u062F \u062E\u064A\u0627\u0631 \u0627\u0644\u062A\u0646\u0632\u064A\u0644 (\u0644\u0644\u062A\u0646\u0632\u064A\u0644\u0627\u062A \u0630\u0627\u062A \u0627\u0644\u0645\u0644\u0641 \u0627\u0644\u0648\u0627\u062D\u062F \u063A\u064A\u0631 \u0627\u0644\u0645\u0636\u063A\u0648\u0637):
|
||||||
|
settings.downloadOption.1=\u0641\u062A\u062D \u0641\u064A \u0646\u0641\u0633 \u0627\u0644\u0646\u0627\u0641\u0630\u0629
|
||||||
|
settings.downloadOption.2=\u0641\u062A\u062D \u0641\u064A \u0646\u0627\u0641\u0630\u0629 \u062C\u062F\u064A\u062F\u0629
|
||||||
|
settings.downloadOption.3=\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u0645\u0644\u0641
|
||||||
|
settings.zipThreshold=\u0645\u0644\u0641\u0627\u062A \u0645\u0636\u063A\u0648\u0637\u0629 \u0639\u0646\u062F \u062A\u062C\u0627\u0648\u0632 \u0639\u062F\u062F \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u0645 \u062A\u0646\u0632\u064A\u0644\u0647\u0627
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
|
#############
|
||||||
|
# HOME-PAGE #
|
||||||
|
#############
|
||||||
|
home.desc=متجرك الشامل المستضاف محليًا لجميع احتياجات PDF الخاصة بك.
|
||||||
|
|
||||||
|
|
||||||
home.multiTool.title=أداة متعددة PDF
|
home.multiTool.title=أداة متعددة PDF
|
||||||
home.multiTool.desc=دمج الصفحات وتدويرها وإعادة ترتيبها وإزالتها
|
home.multiTool.desc=دمج الصفحات وتدويرها وإعادة ترتيبها وإزالتها
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
||||||
|
|
||||||
home.merge.title=دمج ملفات
|
home.merge.title=دمج ملفات
|
||||||
home.merge.desc=دمج ملفات PDF متعددة في ملف واحد بسهولة.
|
home.merge.desc=دمج ملفات PDF متعددة في ملف واحد بسهولة.
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
home.split.title=انقسام ملفات
|
home.split.title=انقسام ملفات
|
||||||
home.split.desc=تقسيم ملفات PDF إلى مستندات متعددة
|
home.split.desc=تقسيم ملفات PDF إلى مستندات متعددة
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
home.rotate.title=تدوير ملفات
|
home.rotate.title=تدوير ملفات
|
||||||
home.rotate.desc=قم بتدوير ملفات PDF الخاصة بك بسهولة.
|
home.rotate.desc=قم بتدوير ملفات PDF الخاصة بك بسهولة.
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=صورة إلى PDF
|
home.imageToPdf.title=صورة إلى PDF
|
||||||
home.imageToPdf.desc=تحويل الصور (PNG ، JPEG ، GIF) إلى PDF.
|
home.imageToPdf.desc=تحويل الصور (PNG ، JPEG ، GIF) إلى PDF.
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfToImage.title=تحويل PDF إلى صورة
|
home.pdfToImage.title=تحويل PDF إلى صورة
|
||||||
home.pdfToImage.desc=تحويل ملف PDF إلى صورة. (PNG ، JPEG ، GIF)
|
home.pdfToImage.desc=تحويل ملف PDF إلى صورة. (PNG ، JPEG ، GIF)
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfOrganiser.title=منظم
|
home.pdfOrganiser.title=منظم
|
||||||
home.pdfOrganiser.desc=إزالة / إعادة ترتيب الصفحات بأي ترتيب
|
home.pdfOrganiser.desc=إزالة / إعادة ترتيب الصفحات بأي ترتيب
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=إضافة صورة إلى ملف PDF
|
home.addImage.title=إضافة صورة إلى ملف PDF
|
||||||
home.addImage.desc=إضافة صورة إلى موقع معين في PDF (العمل قيد التقدم)
|
home.addImage.desc=إضافة صورة إلى موقع معين في PDF (العمل قيد التقدم)
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
home.watermark.title=إضافة علامة مائية
|
home.watermark.title=إضافة علامة مائية
|
||||||
home.watermark.desc=أضف علامة مائية مخصصة إلى مستند PDF الخاص بك.
|
home.watermark.desc=أضف علامة مائية مخصصة إلى مستند PDF الخاص بك.
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
home.remove-watermark.title=\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
|
|
||||||
home.remove-watermark.desc=\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0627\u062A \u0627\u0644\u0645\u0627\u0626\u064A\u0629 \u0645\u0646 \u0645\u0633\u062A\u0646\u062F PDF \u0627\u0644\u062E\u0627\u0635 \u0628\u0643.
|
|
||||||
|
|
||||||
home.permissions.title=تغيير الأذونات
|
home.permissions.title=تغيير الأذونات
|
||||||
home.permissions.desc=قم بتغيير أذونات مستند PDF الخاص بك
|
home.permissions.desc=قم بتغيير أذونات مستند PDF الخاص بك
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=إزالة الصفحات
|
home.removePages.title=إزالة الصفحات
|
||||||
home.removePages.desc=حذف الصفحات غير المرغوب فيها من مستند PDF الخاص بك.
|
home.removePages.desc=حذف الصفحات غير المرغوب فيها من مستند PDF الخاص بك.
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
home.addPassword.title=إضافة كلمة مرور
|
home.addPassword.title=إضافة كلمة مرور
|
||||||
home.addPassword.desc=تشفير مستند PDF الخاص بك بكلمة مرور.
|
home.addPassword.desc=تشفير مستند PDF الخاص بك بكلمة مرور.
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
home.removePassword.title=إزالة كلمة المرور
|
home.removePassword.title=إزالة كلمة المرور
|
||||||
home.removePassword.desc=إزالة الحماية بكلمة مرور من مستند PDF الخاص بك.
|
home.removePassword.desc=إزالة الحماية بكلمة مرور من مستند PDF الخاص بك.
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
home.compressPdfs.title=ضغط ملفات
|
home.compressPdfs.title=ضغط ملفات
|
||||||
home.compressPdfs.desc=ضغط ملفات PDF لتقليل حجم الملف.
|
home.compressPdfs.desc=ضغط ملفات PDF لتقليل حجم الملف.
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=\u062A\u063A\u064A\u064A\u0631 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0648\u0635\u0641\u064A\u0629
|
home.changeMetadata.title=\u062A\u063A\u064A\u064A\u0631 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0648\u0635\u0641\u064A\u0629
|
||||||
home.changeMetadata.desc=\u062A\u063A\u064A\u064A\u0631 / \u0625\u0632\u0627\u0644\u0629 / \u0625\u0636\u0627\u0641\u0629 \u0628\u064A\u0627\u0646\u0627\u062A \u0623\u0648\u0644\u064A\u0629 \u0645\u0646 \u0645\u0633\u062A\u0646\u062F PDF
|
home.changeMetadata.desc=\u062A\u063A\u064A\u064A\u0631 / \u0625\u0632\u0627\u0644\u0629 / \u0625\u0636\u0627\u0641\u0629 \u0628\u064A\u0627\u0646\u0627\u062A \u0623\u0648\u0644\u064A\u0629 \u0645\u0646 \u0645\u0633\u062A\u0646\u062F PDF
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
home.fileToPDF.title=\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
||||||
home.fileToPDF.desc=\u062A\u062D\u0648\u064A\u0644 \u0623\u064A \u0645\u0644\u0641 \u062A\u0642\u0631\u064A\u0628\u0627 \u0625\u0644\u0649 PDF (DOCX \u0648PNG \u0648XLS \u0648PPT \u0648TXT \u0648\u0627\u0644\u0645\u0632\u064A\u062F)
|
home.fileToPDF.desc=\u062A\u062D\u0648\u064A\u0644 \u0623\u064A \u0645\u0644\u0641 \u062A\u0642\u0631\u064A\u0628\u0627 \u0625\u0644\u0649 PDF (DOCX \u0648PNG \u0648XLS \u0648PPT \u0648TXT \u0648\u0627\u0644\u0645\u0632\u064A\u062F)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=\u062A\u0634\u063A\u064A\u0644 OCR \u0639\u0644\u0649 PDF \u0648 / \u0623\u0648 \u0645\u0633\u062D \u0636\u0648\u0626\u064A
|
home.ocr.title=\u062A\u0634\u063A\u064A\u0644 OCR \u0639\u0644\u0649 PDF \u0648 / \u0623\u0648 \u0645\u0633\u062D \u0636\u0648\u0626\u064A
|
||||||
home.ocr.desc=\u064A\u0642\u0648\u0645 \u0628\u0631\u0646\u0627\u0645\u062C \u0627\u0644\u062A\u0646\u0638\u064A\u0641 \u0628\u0645\u0633\u062D \u0648\u0627\u0643\u062A\u0634\u0627\u0641 \u0627\u0644\u0646\u0635 \u0645\u0646 \u0627\u0644\u0635\u0648\u0631 \u062F\u0627\u062E\u0644 \u0645\u0644\u0641 PDF \u0648\u064A\u0639\u064A\u062F \u0625\u0636\u0627\u0641\u062A\u0647 \u0643\u0646\u0635
|
home.ocr.desc=\u064A\u0642\u0648\u0645 \u0628\u0631\u0646\u0627\u0645\u062C \u0627\u0644\u062A\u0646\u0638\u064A\u0641 \u0628\u0645\u0633\u062D \u0648\u0627\u0643\u062A\u0634\u0627\u0641 \u0627\u0644\u0646\u0635 \u0645\u0646 \u0627\u0644\u0635\u0648\u0631 \u062F\u0627\u062E\u0644 \u0645\u0644\u0641 PDF \u0648\u064A\u0639\u064A\u062F \u0625\u0636\u0627\u0641\u062A\u0647 \u0643\u0646\u0635
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
home.extractImages.title=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
home.extractImages.title=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
||||||
home.extractImages.desc=\u064A\u0633\u062A\u062E\u0631\u062C \u062C\u0645\u064A\u0639 \u0627\u0644\u0635\u0648\u0631 \u0645\u0646 \u0645\u0644\u0641 PDF \u0648\u064A\u062D\u0641\u0638\u0647\u0627 \u0641\u064A \u0627\u0644\u0631\u0645\u0632 \u0627\u0644\u0628\u0631\u064A\u062F\u064A
|
home.extractImages.desc=\u064A\u0633\u062A\u062E\u0631\u062C \u062C\u0645\u064A\u0639 \u0627\u0644\u0635\u0648\u0631 \u0645\u0646 \u0645\u0644\u0641 PDF \u0648\u064A\u062D\u0641\u0638\u0647\u0627 \u0641\u064A \u0627\u0644\u0631\u0645\u0632 \u0627\u0644\u0628\u0631\u064A\u062F\u064A
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
home.pdfToPDFA.title=\u062A\u062D\u0648\u064A\u0644 \u0645\u0644\u0641\u0627\u062A PDF \u0625\u0644\u0649 PDF / A
|
home.pdfToPDFA.title=\u062A\u062D\u0648\u064A\u0644 \u0645\u0644\u0641\u0627\u062A PDF \u0625\u0644\u0649 PDF / A
|
||||||
home.pdfToPDFA.desc=\u062A\u062D\u0648\u064A\u0644 PDF \u0625\u0644\u0649 PDF / A \u0644\u0644\u062A\u062E\u0632\u064A\u0646 \u0637\u0648\u064A\u0644 \u0627\u0644\u0645\u062F\u0649
|
home.pdfToPDFA.desc=\u062A\u062D\u0648\u064A\u0644 PDF \u0625\u0644\u0649 PDF / A \u0644\u0644\u062A\u062E\u0632\u064A\u0646 \u0637\u0648\u064A\u0644 \u0627\u0644\u0645\u062F\u0649
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
home.PDFToWord.title=تحويل PDF إلى Word
|
home.PDFToWord.title=تحويل PDF إلى Word
|
||||||
home.PDFToWord.desc=تحويل PDF إلى تنسيقات Word (DOC و DOCX و ODT)
|
home.PDFToWord.desc=تحويل PDF إلى تنسيقات Word (DOC و DOCX و ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDF للعرض التقديمي
|
home.PDFToPresentation.title=PDF للعرض التقديمي
|
||||||
home.PDFToPresentation.desc=تحويل PDF إلى تنسيقات عرض تقديمي (PPT و PPTX و ODP)
|
home.PDFToPresentation.desc=تحويل PDF إلى تنسيقات عرض تقديمي (PPT و PPTX و ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=تحويل PDF إلى نص / RTF
|
home.PDFToText.title=تحويل PDF إلى نص / RTF
|
||||||
home.PDFToText.desc=تحويل PDF إلى تنسيق نص أو RTF
|
home.PDFToText.desc=تحويل PDF إلى تنسيق نص أو RTF
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
home.PDFToHTML.title=تحويل PDF إلى HTML
|
home.PDFToHTML.title=تحويل PDF إلى HTML
|
||||||
home.PDFToHTML.desc=تحويل PDF إلى تنسيق HTML
|
home.PDFToHTML.desc=تحويل PDF إلى تنسيق HTML
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=تحويل PDF إلى XML
|
home.PDFToXML.title=تحويل PDF إلى XML
|
||||||
home.PDFToXML.desc=تحويل PDF إلى تنسيق XML
|
home.PDFToXML.desc=تحويل PDF إلى تنسيق XML
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
home.ScannerImageSplit.title=كشف / انقسام الصور الممسوحة ضوئيًا
|
home.ScannerImageSplit.title=كشف / انقسام الصور الممسوحة ضوئيًا
|
||||||
home.ScannerImageSplit.desc=تقسيم عدة صور من داخل صورة / ملف PDF
|
home.ScannerImageSplit.desc=تقسيم عدة صور من داخل صورة / ملف PDF
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
home.sign.title = تسجيل الدخول
|
home.sign.title=تسجيل الدخول
|
||||||
home.sign.desc = إضافة التوقيع إلى PDF عن طريق الرسم أو النص أو الصورة
|
home.sign.desc=إضافة التوقيع إلى PDF عن طريق الرسم أو النص أو الصورة
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
home.flatten.title = تسطيح
|
home.flatten.title=تسطيح
|
||||||
home.flatten.desc = قم بإزالة كافة العناصر والنماذج التفاعلية من ملف PDF
|
home.flatten.desc=قم بإزالة كافة العناصر والنماذج التفاعلية من ملف PDF
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
home.repair.title = إصلاح
|
home.repair.title=إصلاح
|
||||||
home.repair.desc = يحاول إصلاح ملف PDF تالف / معطل
|
home.repair.desc=يحاول إصلاح ملف PDF تالف / معطل
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
home.removeBlanks.title = إزالة الصفحات الفارغة
|
home.removeBlanks.title=إزالة الصفحات الفارغة
|
||||||
home.removeBlanks.desc = يكتشف ويزيل الصفحات الفارغة من المستند
|
home.removeBlanks.desc=يكتشف ويزيل الصفحات الفارغة من المستند
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
|
|
||||||
|
home.compare.title=قارن
|
||||||
|
home.compare.desc=يقارن ويظهر الاختلافات بين 2 من مستندات PDF
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
home.certSign.title=Sign with Certificate
|
home.certSign.title=Sign with Certificate
|
||||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
home.compare.title = قارن
|
|
||||||
home.compare.desc = يقارن ويظهر الاختلافات بين 2 من مستندات PDF
|
|
||||||
|
|
||||||
home.pageLayout.title=Multi-Page Layout
|
home.pageLayout.title=Multi-Page Layout
|
||||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
home.scalePages.title=Adjust page size/scale
|
home.scalePages.title=Adjust page size/scale
|
||||||
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
downloadPdf = تنزيل PDF
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
text=نص
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
font=الخط
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
selectFillter = - حدد -
|
|
||||||
pageNum = رقم الصفحة
|
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Multi Page Layout
|
pageLayout.title=Multi Page Layout
|
||||||
pageLayout.header=Multi Page Layout
|
pageLayout.header=Multi Page Layout
|
||||||
pageLayout.pagesPerSheet=Pages per sheet:
|
pageLayout.pagesPerSheet=Pages per sheet:
|
||||||
pageLayout.submit=Submit
|
pageLayout.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Adjust page-scale
|
scalePages.title=Adjust page-scale
|
||||||
scalePages.header=Adjust page-scale
|
scalePages.header=Adjust page-scale
|
||||||
scalePages.pageSize=Size of a page of the document.
|
scalePages.pageSize=Size of a page of the document.
|
||||||
scalePages.scaleFactor=Zoom level (crop) of a page.
|
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||||
scalePages.submit=Submit
|
scalePages.submit=Submit
|
||||||
|
|
||||||
certSign.title = توقيع الشهادة
|
|
||||||
certSign.header = قم بتوقيع ملف PDF بشهادتك (العمل قيد التقدم)
|
|
||||||
certSign.selectPDF = حدد ملف PDF للتوقيع:
|
|
||||||
certSign.selectKey = حدد ملف المفتاح الخاص (تنسيق PKCS # 8 ، يمكن أن يكون .pem أو .der):
|
|
||||||
certSign.selectCert = حدد ملف الشهادة الخاص بك (تنسيق X.509 ، يمكن أن يكون .pem أو .der):
|
|
||||||
certSign.selectP12 = حدد ملف تخزين المفاتيح PKCS # 12 (.p12 أو .pfx) (اختياري ، إذا تم توفيره ، يجب أن يحتوي على مفتاحك الخاص وشهادتك):
|
|
||||||
certSign.certType = نوع الشهادة
|
|
||||||
certSign.password = أدخل ملف تخزين المفاتيح أو كلمة المرور الخاصة (إن وجدت):
|
|
||||||
certSign.showSig = إظهار التوقيع
|
|
||||||
certSign.reason = السبب
|
|
||||||
certSign.location = الموقع
|
|
||||||
certSign.name = الاسم
|
|
||||||
certSign.submit = تسجيل PDF
|
|
||||||
|
|
||||||
removeBlanks.title = إزالة الفراغات
|
#certSign
|
||||||
removeBlanks.header = إزالة الصفحات الفارغة
|
certSign.title=توقيع الشهادة
|
||||||
removeBlanks.threshold = العتبة:
|
certSign.header=قم بتوقيع ملف PDF بشهادتك (العمل قيد التقدم)
|
||||||
removeBlanks.thresholdDesc = الحد الفاصل لتحديد مدى بياض البكسل الأبيض
|
certSign.selectPDF=حدد ملف PDF للتوقيع:
|
||||||
removeBlanks.whitePercent = نسبة الأبيض (٪):
|
certSign.selectKey=حدد ملف المفتاح الخاص (تنسيق PKCS # 8 ، يمكن أن يكون .pem أو .der):
|
||||||
removeBlanks.whitePercentDesc = النسبة المئوية للصفحة التي يجب أن تكون بيضاء لتتم إزالتها
|
certSign.selectCert=حدد ملف الشهادة الخاص بك (تنسيق X.509 ، يمكن أن يكون .pem أو .der):
|
||||||
removeBlanks.submit = إزالة الفراغات
|
certSign.selectP12=حدد ملف تخزين المفاتيح PKCS # 12 (.p12 أو .pfx) (اختياري ، إذا تم توفيره ، يجب أن يحتوي على مفتاحك الخاص وشهادتك):
|
||||||
|
certSign.certType=نوع الشهادة
|
||||||
|
certSign.password=أدخل ملف تخزين المفاتيح أو كلمة المرور الخاصة (إن وجدت):
|
||||||
|
certSign.showSig=إظهار التوقيع
|
||||||
|
certSign.reason=السبب
|
||||||
|
certSign.location=الموقع
|
||||||
|
certSign.name=الاسم
|
||||||
|
certSign.submit=تسجيل PDF
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
|
removeBlanks.title=إزالة الفراغات
|
||||||
|
removeBlanks.header=إزالة الصفحات الفارغة
|
||||||
|
removeBlanks.threshold=العتبة:
|
||||||
|
removeBlanks.thresholdDesc=الحد الفاصل لتحديد مدى بياض البكسل الأبيض
|
||||||
|
removeBlanks.whitePercent=نسبة الأبيض (٪):
|
||||||
|
removeBlanks.whitePercentDesc=النسبة المئوية للصفحة التي يجب أن تكون بيضاء لتتم إزالتها
|
||||||
|
removeBlanks.submit=إزالة الفراغات
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=يقارن
|
compare.title=يقارن
|
||||||
compare.header=قارن ملفات PDF
|
compare.header=قارن ملفات PDF
|
||||||
compare.document.1=المستند 1
|
compare.document.1=المستند 1
|
||||||
compare.document.2=المستند 2
|
compare.document.2=المستند 2
|
||||||
compare.submit=يقارن
|
compare.submit=يقارن
|
||||||
|
|
||||||
sign.title = تسجيل الدخول
|
|
||||||
sign.header = توقيع ملفات PDF
|
|
||||||
sign.upload = تحميل الصورة
|
|
||||||
sign.draw = رسم التوقيع
|
|
||||||
Sign.text = إدخال النص
|
|
||||||
|
|
||||||
|
#sign
|
||||||
|
sign.title=تسجيل الدخول
|
||||||
|
sign.header=توقيع ملفات PDF
|
||||||
|
sign.upload=تحميل الصورة
|
||||||
|
sign.draw=رسم التوقيع
|
||||||
|
sign.text=Text Input
|
||||||
sign.clear=واضح
|
sign.clear=واضح
|
||||||
sign.add = إضافة
|
sign.add=إضافة
|
||||||
|
|
||||||
repair.title = إصلاح
|
|
||||||
repair.header = إصلاح ملفات PDF
|
|
||||||
repair.submit = الإصلاح
|
|
||||||
|
|
||||||
flatten.title = تسطيح
|
#repair
|
||||||
flatten.header = تسوية ملفات PDF
|
repair.title=إصلاح
|
||||||
flatten.submit = تسطيح
|
repair.header=إصلاح ملفات PDF
|
||||||
|
repair.submit=الإصلاح
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
|
flatten.title=تسطيح
|
||||||
|
flatten.header=تسوية ملفات PDF
|
||||||
|
flatten.submit=تسطيح
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=عتبة الزاوية:
|
ScannerImageSplit.selectText.1=عتبة الزاوية:
|
||||||
ScannerImageSplit.selectText.2=تعيين الحد الأدنى للزاوية المطلقة المطلوبة لتدوير الصورة (افتراضي: 10).
|
ScannerImageSplit.selectText.2=تعيين الحد الأدنى للزاوية المطلقة المطلوبة لتدوير الصورة (افتراضي: 10).
|
||||||
ScannerImageSplit.selectText.3=التسامح:
|
ScannerImageSplit.selectText.3=التسامح:
|
||||||
@@ -217,16 +532,6 @@ ScannerImageSplit.selectText.9=حجم الحدود:
|
|||||||
ScannerImageSplit.selectText.10=يضبط حجم الحدود المضافة والمزالة لمنع الحدود البيضاء في الإخراج (الافتراضي: 1).
|
ScannerImageSplit.selectText.10=يضبط حجم الحدود المضافة والمزالة لمنع الحدود البيضاء في الإخراج (الافتراضي: 1).
|
||||||
|
|
||||||
|
|
||||||
navbar.settings=\u0625\u0639\u062F\u0627\u062F\u0627\u062A
|
|
||||||
settings.title=\u0627\u0644\u0625\u0639\u062F\u0627\u062F\u0627\u062A
|
|
||||||
settings.update=\u0627\u0644\u062A\u062D\u062F\u064A\u062B \u0645\u062A\u0627\u062D
|
|
||||||
settings.appVersion=\u0625\u0635\u062F\u0627\u0631 \u0627\u0644\u062A\u0637\u0628\u064A\u0642:
|
|
||||||
settings.downloadOption.title=\u062A\u062D\u062F\u064A\u062F \u062E\u064A\u0627\u0631 \u0627\u0644\u062A\u0646\u0632\u064A\u0644 (\u0644\u0644\u062A\u0646\u0632\u064A\u0644\u0627\u062A \u0630\u0627\u062A \u0627\u0644\u0645\u0644\u0641 \u0627\u0644\u0648\u0627\u062D\u062F \u063A\u064A\u0631 \u0627\u0644\u0645\u0636\u063A\u0648\u0637):
|
|
||||||
settings.downloadOption.1=\u0641\u062A\u062D \u0641\u064A \u0646\u0641\u0633 \u0627\u0644\u0646\u0627\u0641\u0630\u0629
|
|
||||||
settings.downloadOption.2=\u0641\u062A\u062D \u0641\u064A \u0646\u0627\u0641\u0630\u0629 \u062C\u062F\u064A\u062F\u0629
|
|
||||||
settings.downloadOption.3=\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u0645\u0644\u0641
|
|
||||||
settings.zipThreshold=\u0645\u0644\u0641\u0627\u062A \u0645\u0636\u063A\u0648\u0637\u0629 \u0639\u0646\u062F \u062A\u062C\u0627\u0648\u0632 \u0639\u062F\u062F \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u0645 \u062A\u0646\u0632\u064A\u0644\u0647\u0627
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=\u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 / \u062A\u0646\u0638\u064A\u0641 \u0627\u0644\u0645\u0633\u062D \u0627\u0644\u0636\u0648\u0626\u064A
|
ocr.title=\u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 / \u062A\u0646\u0638\u064A\u0641 \u0627\u0644\u0645\u0633\u062D \u0627\u0644\u0636\u0648\u0626\u064A
|
||||||
ocr.header=\u0645\u0633\u062D \u0627\u0644\u0645\u0633\u062D \u0627\u0644\u0636\u0648\u0626\u064A / \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 (\u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641)
|
ocr.header=\u0645\u0633\u062D \u0627\u0644\u0645\u0633\u062D \u0627\u0644\u0636\u0648\u0626\u064A / \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641 (\u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641)
|
||||||
@@ -240,19 +545,21 @@ ocr.selectText.7=\u0641\u0631\u0636 \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\
|
|||||||
ocr.selectText.8=\u0639\u0627\u062F\u064A (\u062E\u0637\u0623 \u0625\u0630\u0627 \u0643\u0627\u0646 PDF \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0646\u0635)
|
ocr.selectText.8=\u0639\u0627\u062F\u064A (\u062E\u0637\u0623 \u0625\u0630\u0627 \u0643\u0627\u0646 PDF \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0646\u0635)
|
||||||
ocr.selectText.9=\u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0625\u0636\u0627\u0641\u064A\u0629
|
ocr.selectText.9=\u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0625\u0636\u0627\u0641\u064A\u0629
|
||||||
ocr.selectText.10=\u0648\u0636\u0639 \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641
|
ocr.selectText.10=\u0648\u0636\u0639 \u0627\u0644\u062A\u0639\u0631\u0641 \u0627\u0644\u0636\u0648\u0626\u064A \u0639\u0644\u0649 \u0627\u0644\u062D\u0631\u0648\u0641
|
||||||
ocr.selectText.11 = إزالة الصور بعد التعرف الضوئي على الحروف (يزيل كل الصور ، يكون مفيدًا فقط إذا كان جزءًا من خطوة التحويل)
|
ocr.selectText.11=إزالة الصور بعد التعرف الضوئي على الحروف (يزيل كل الصور ، يكون مفيدًا فقط إذا كان جزءًا من خطوة التحويل)
|
||||||
ocr.selectText.12 = نوع العرض (متقدم)
|
ocr.selectText.12=نوع العرض (متقدم)
|
||||||
ocr.help=\u064A\u0631\u062C\u0649 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0648\u062B\u0627\u0626\u0642 \u062D\u0648\u0644 \u0643\u064A\u0641\u064A\u0629 \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0647\u0630\u0627 \u0644\u0644\u063A\u0627\u062A \u0623\u062E\u0631\u0649 \u0648 / \u0623\u0648 \u0627\u0644\u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0644\u064A\u0633 \u0641\u064A \u0639\u0627\u0645\u0644 \u0627\u0644\u0625\u0631\u0633\u0627\u0621
|
ocr.help=\u064A\u0631\u062C\u0649 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0648\u062B\u0627\u0626\u0642 \u062D\u0648\u0644 \u0643\u064A\u0641\u064A\u0629 \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0647\u0630\u0627 \u0644\u0644\u063A\u0627\u062A \u0623\u062E\u0631\u0649 \u0648 / \u0623\u0648 \u0627\u0644\u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0644\u064A\u0633 \u0641\u064A \u0639\u0627\u0645\u0644 \u0627\u0644\u0625\u0631\u0633\u0627\u0621
|
||||||
ocr.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 OCRmyPDF \u0648 Tesseract \u0644 OCR.
|
ocr.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 OCRmyPDF \u0648 Tesseract \u0644 OCR.
|
||||||
ocr.submit=\u0645\u0639\u0627\u0644\u062C\u0629 PDF \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 OCR
|
ocr.submit=\u0645\u0639\u0627\u0644\u062C\u0629 PDF \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 OCR
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
extractImages.title=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
||||||
extractImages.header=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
extractImages.header=\u0627\u0633\u062A\u062E\u0631\u0627\u062C \u0627\u0644\u0635\u0648\u0631
|
||||||
extractImages.selectText=\u062D\u062F\u062F \u062A\u0646\u0633\u064A\u0642 \u0627\u0644\u0635\u0648\u0631\u0629 \u0644\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0635\u0648\u0631 \u0627\u0644\u0645\u0633\u062A\u062E\u0631\u062C\u0629 \u0625\u0644\u0649
|
extractImages.selectText=\u062D\u062F\u062F \u062A\u0646\u0633\u064A\u0642 \u0627\u0644\u0635\u0648\u0631\u0629 \u0644\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0635\u0648\u0631 \u0627\u0644\u0645\u0633\u062A\u062E\u0631\u062C\u0629 \u0625\u0644\u0649
|
||||||
extractImages.submit=\u0627\u0633\u062A\u062E\u0631\u0627\u062C
|
extractImages.submit=\u0627\u0633\u062A\u062E\u0631\u0627\u062C
|
||||||
|
|
||||||
#File \u0625\u0644\u0649 PDF
|
|
||||||
|
#File to PDF
|
||||||
fileToPDF.title=\u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
fileToPDF.title=\u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
||||||
fileToPDF.header=\u062A\u062D\u0648\u064A\u0644 \u0623\u064A \u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
fileToPDF.header=\u062A\u062D\u0648\u064A\u0644 \u0623\u064A \u0645\u0644\u0641 \u0625\u0644\u0649 PDF
|
||||||
fileToPDF.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 \u0644\u064A\u0628\u0631 \u0623\u0648\u0641\u064A\u0633 \u0648\u0623\u0648\u0646\u0648\u0643\u0648\u0646\u0641 \u0644\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0645\u0644\u0641\u0627\u062A.
|
fileToPDF.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 \u0644\u064A\u0628\u0631 \u0623\u0648\u0641\u064A\u0633 \u0648\u0623\u0648\u0646\u0648\u0643\u0648\u0646\u0641 \u0644\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0645\u0644\u0641\u0627\u062A.
|
||||||
@@ -260,6 +567,18 @@ fileToPDF.supportedFileTypes=\u064A\u062C\u0628 \u0623\u0646 \u062A\u062A\u0636\
|
|||||||
fileToPDF.submit=\u062A\u062D\u0648\u064A\u0644 \u0625\u0644\u0649 PDF
|
fileToPDF.submit=\u062A\u062D\u0648\u064A\u0644 \u0625\u0644\u0649 PDF
|
||||||
|
|
||||||
|
|
||||||
|
#compress
|
||||||
|
compress.title=ضغط
|
||||||
|
compress.header=ضغط ملف PDF
|
||||||
|
compress.credit=تستخدم هذه الخدمة OCRmyPDF لضغط / تحسين PDF.
|
||||||
|
compress.selectText.1=الوضع اليدوي - من 1 إلى 4
|
||||||
|
compress.selectText.2=مستوى التحسين:
|
||||||
|
compress.selectText.3=4 (رهيب للصور النصية)
|
||||||
|
compress.selectText.4=الوضع التلقائي - يضبط الجودة تلقائيًا للحصول على ملف PDF بالحجم المحدد
|
||||||
|
compress.selectText.5=حجم PDF المتوقع (على سبيل المثال 25 ميجا بايت ، 10.8 ميجا بايت ، 25 كيلو بايت)
|
||||||
|
compress.submit=ضغطضغط
|
||||||
|
|
||||||
|
|
||||||
#Add image
|
#Add image
|
||||||
addImage.title=إضافة صورة
|
addImage.title=إضافة صورة
|
||||||
addImage.header=إضافة صورة إلى PDF
|
addImage.header=إضافة صورة إلى PDF
|
||||||
@@ -267,38 +586,33 @@ addImage.everyPage=كل صفحة؟
|
|||||||
addImage.upload=إضافة صورة
|
addImage.upload=إضافة صورة
|
||||||
addImage.submit=إضافة صورة
|
addImage.submit=إضافة صورة
|
||||||
|
|
||||||
#compress
|
|
||||||
compress.title = ضغط
|
|
||||||
compress.header = ضغط ملف PDF
|
|
||||||
compress.credit = تستخدم هذه الخدمة OCRmyPDF لضغط / تحسين PDF.
|
|
||||||
compress.selectText.1 = الوضع اليدوي - من 1 إلى 4
|
|
||||||
compress.selectText.2 = مستوى التحسين:
|
|
||||||
compress.selectText.3 = 4 (رهيب للصور النصية)
|
|
||||||
compress.selectText.4 = الوضع التلقائي - يضبط الجودة تلقائيًا للحصول على ملف PDF بالحجم المحدد
|
|
||||||
compress.selectText.5 = حجم PDF المتوقع (على سبيل المثال 25 ميجا بايت ، 10.8 ميجا بايت ، 25 كيلو بايت)
|
|
||||||
compress.submit = ضغطضغط
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
merge.title=دمج
|
merge.title=دمج
|
||||||
merge.header=دمج ملفات PDF متعددة (2+)
|
merge.header=دمج ملفات PDF متعددة (2+)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=دمج
|
merge.submit=دمج
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=منظم الصفحة
|
pdfOrganiser.title=منظم الصفحة
|
||||||
pdfOrganiser.header=منظم صفحات PDF
|
pdfOrganiser.header=منظم صفحات PDF
|
||||||
pdfOrganiser.submit=إعادة ترتيب الصفحات
|
pdfOrganiser.submit=إعادة ترتيب الصفحات
|
||||||
|
|
||||||
|
|
||||||
#multiTool
|
#multiTool
|
||||||
multiTool.title=أداة متعددة PDF
|
multiTool.title=أداة متعددة PDF
|
||||||
multiTool.header=أداة متعددة PDF
|
multiTool.header=أداة متعددة PDF
|
||||||
|
|
||||||
|
|
||||||
#pageRemover
|
#pageRemover
|
||||||
pageRemover.title=مزيل الصفحة
|
pageRemover.title=مزيل الصفحة
|
||||||
pageRemover.header=مزيل صفحة PDF
|
pageRemover.header=مزيل صفحة PDF
|
||||||
pageRemover.pagesToDelete=الصفحات المراد حذفها (أدخل قائمة بأرقام الصفحات مفصولة بفواصل):
|
pageRemover.pagesToDelete=الصفحات المراد حذفها (أدخل قائمة بأرقام الصفحات مفصولة بفواصل):
|
||||||
pageRemover.submit=حذف الصفحات
|
pageRemover.submit=حذف الصفحات
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=تدوير PDF
|
rotate.title=تدوير PDF
|
||||||
rotate.header=تدوير PDF
|
rotate.header=تدوير PDF
|
||||||
@@ -306,8 +620,6 @@ rotate.selectAngle=حدد زاوية الدوران (بمضاعفات 90 درج
|
|||||||
rotate.submit=استدارة
|
rotate.submit=استدارة
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=انقسام PDF
|
split.title=انقسام PDF
|
||||||
split.header=تقسيم PDF
|
split.header=تقسيم PDF
|
||||||
@@ -333,6 +645,7 @@ imageToPDF.selectText.3=\u0627\u0644\u0645\u0646\u0637\u0642 \u0627\u0644\u0645\
|
|||||||
imageToPDF.selectText.4=\u062F\u0645\u062C \u0641\u064A \u0645\u0644\u0641 PDF \u0648\u0627\u062D\u062F
|
imageToPDF.selectText.4=\u062F\u0645\u062C \u0641\u064A \u0645\u0644\u0641 PDF \u0648\u0627\u062D\u062F
|
||||||
imageToPDF.selectText.5=\u062A\u062D\u0648\u064A\u0644 \u0625\u0644\u0649 \u0645\u0644\u0641\u0627\u062A PDF \u0645\u0646\u0641\u0635\u0644\u0629
|
imageToPDF.selectText.5=\u062A\u062D\u0648\u064A\u0644 \u0625\u0644\u0649 \u0645\u0644\u0641\u0627\u062A PDF \u0645\u0646\u0641\u0635\u0644\u0629
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=تحويل PDF إلى صورة
|
pdfToImage.title=تحويل PDF إلى صورة
|
||||||
pdfToImage.header=تحويل PDF إلى صورة
|
pdfToImage.header=تحويل PDF إلى صورة
|
||||||
@@ -346,6 +659,7 @@ pdfToImage.grey=\u062A\u062F\u0631\u062C \u0627\u0644\u0631\u0645\u0627\u062F\u0
|
|||||||
pdfToImage.blackwhite=\u0623\u0628\u064A\u0636 \u0648\u0623\u0633\u0648\u062F (\u0642\u062F \u064A\u0641\u0642\u062F \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A!)
|
pdfToImage.blackwhite=\u0623\u0628\u064A\u0636 \u0648\u0623\u0633\u0648\u062F (\u0642\u062F \u064A\u0641\u0642\u062F \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A!)
|
||||||
pdfToImage.submit=تحول
|
pdfToImage.submit=تحول
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=إضافة كلمة مرور
|
addPassword.title=إضافة كلمة مرور
|
||||||
addPassword.header=إضافة كلمة مرور (تشفير)
|
addPassword.header=إضافة كلمة مرور (تشفير)
|
||||||
@@ -367,6 +681,7 @@ addPassword.selectText.15=Restricts what can be done with the document once it i
|
|||||||
addPassword.selectText.16=Restricts the opening of the document itself
|
addPassword.selectText.16=Restricts the opening of the document itself
|
||||||
addPassword.submit=تشفير
|
addPassword.submit=تشفير
|
||||||
|
|
||||||
|
|
||||||
#watermark
|
#watermark
|
||||||
watermark.title=إضافة علامة مائية
|
watermark.title=إضافة علامة مائية
|
||||||
watermark.header=إضافة علامة مائية
|
watermark.header=إضافة علامة مائية
|
||||||
@@ -377,14 +692,10 @@ watermark.selectText.4=دوران (0-360):
|
|||||||
watermark.selectText.5=widthSpacer (مسافة بين كل علامة مائية أفقيًا):
|
watermark.selectText.5=widthSpacer (مسافة بين كل علامة مائية أفقيًا):
|
||||||
watermark.selectText.6=heightSpacer (مسافة بين كل علامة مائية عموديًا):
|
watermark.selectText.6=heightSpacer (مسافة بين كل علامة مائية عموديًا):
|
||||||
watermark.selectText.7=\u0627\u0644\u062A\u0639\u062A\u064A\u0645 (0\u066A - 100\u066A):
|
watermark.selectText.7=\u0627\u0644\u062A\u0639\u062A\u064A\u0645 (0\u066A - 100\u066A):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=إضافة علامة مائية
|
watermark.submit=إضافة علامة مائية
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
|
|
||||||
remove-watermark.header=\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
|
|
||||||
remove-watermark.selectText.1=\u062D\u062F\u062F PDF \u0644\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629 \u0645\u0646:
|
|
||||||
remove-watermark.selectText.2=\u0646\u0635 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629:
|
|
||||||
remove-watermark.submit=\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=تغيير الأذونات
|
permissions.title=تغيير الأذونات
|
||||||
@@ -402,6 +713,7 @@ permissions.selectText.9=منع الطباعة
|
|||||||
permissions.selectText.10=منع طباعة التنسيقات المختلفة
|
permissions.selectText.10=منع طباعة التنسيقات المختلفة
|
||||||
permissions.submit=تغيير
|
permissions.submit=تغيير
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=إزالة كلمة المرور
|
removePassword.title=إزالة كلمة المرور
|
||||||
removePassword.header=إزالة كلمة المرور (فك التشفير)
|
removePassword.header=إزالة كلمة المرور (فك التشفير)
|
||||||
@@ -409,7 +721,9 @@ removePassword.selectText.1=حدد PDF لفك التشفير
|
|||||||
removePassword.selectText.2=كلمة المرور
|
removePassword.selectText.2=كلمة المرور
|
||||||
removePassword.submit=إزالة
|
removePassword.submit=إزالة
|
||||||
|
|
||||||
changeMetadata.title=\u062A\u063A\u064A\u064A\u0631 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0648\u0635\u0641\u064A\u0629
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=\u0627\u0644\u0639\u0646\u0648\u0627\u0646:
|
||||||
changeMetadata.header=\u062A\u063A\u064A\u064A\u0631 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0648\u0635\u0641\u064A\u0629
|
changeMetadata.header=\u062A\u063A\u064A\u064A\u0631 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0648\u0635\u0641\u064A\u0629
|
||||||
changeMetadata.selectText.1=\u064A\u0631\u062C\u0649 \u062A\u0639\u062F\u064A\u0644 \u0627\u0644\u0645\u062A\u063A\u064A\u0631\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u0631\u063A\u0628 \u0641\u064A \u062A\u063A\u064A\u064A\u0631\u0647\u0627
|
changeMetadata.selectText.1=\u064A\u0631\u062C\u0649 \u062A\u0639\u062F\u064A\u0644 \u0627\u0644\u0645\u062A\u063A\u064A\u0631\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u0631\u063A\u0628 \u0641\u064A \u062A\u063A\u064A\u064A\u0631\u0647\u0627
|
||||||
changeMetadata.selectText.2=\u062D\u0630\u0641 \u0643\u0644 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0623\u0648\u0644\u064A\u0629
|
changeMetadata.selectText.2=\u062D\u0630\u0641 \u0643\u0644 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0623\u0648\u0644\u064A\u0629
|
||||||
@@ -428,24 +742,29 @@ changeMetadata.selectText.5=\u0625\u0636\u0627\u0641\u0629 \u0625\u062F\u062E\u0
|
|||||||
changeMetadata.submit=\u062A\u063A\u064A\u064A\u0631
|
changeMetadata.submit=\u062A\u063A\u064A\u064A\u0631
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=\u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
|
xlsToPdf.title=\u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
|
||||||
xlsToPdf.header=\u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
|
xlsToPdf.header=\u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
|
||||||
xlsToPdf.selectText.1=\u062D\u062F\u062F \u0648\u0631\u0642\u0629 \u0625\u0643\u0633\u0644 XLS \u0623\u0648 XLSX \u0644\u0644\u062A\u062D\u0648\u064A\u0644
|
xlsToPdf.selectText.1=\u062D\u062F\u062F \u0648\u0631\u0642\u0629 \u0625\u0643\u0633\u0644 XLS \u0623\u0648 XLSX \u0644\u0644\u062A\u062D\u0648\u064A\u0644
|
||||||
xlsToPdf.convert=\u062A\u062D\u0648\u064A\u0644
|
xlsToPdf.convert=\u062A\u062D\u0648\u064A\u0644
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
pdfToPDFA.title=PDF \u0625\u0644\u0649 PDF / A
|
pdfToPDFA.title=PDF \u0625\u0644\u0649 PDF / A
|
||||||
pdfToPDFA.header=PDF \u0625\u0644\u0649 PDF / A
|
pdfToPDFA.header=PDF \u0625\u0644\u0649 PDF / A
|
||||||
pdfToPDFA.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 OCRmyPDF \u0644\u062A\u062D\u0648\u064A\u0644 PDF / A.
|
pdfToPDFA.credit=\u062A\u0633\u062A\u062E\u062F\u0645 \u0647\u0630\u0647 \u0627\u0644\u062E\u062F\u0645\u0629 OCRmyPDF \u0644\u062A\u062D\u0648\u064A\u0644 PDF / A.
|
||||||
pdfToPDFA.submit=\u062A\u062D\u0648\u064A\u0644
|
pdfToPDFA.submit=\u062A\u062D\u0648\u064A\u0644
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=تحويل PDF إلى Word
|
PDFToWord.title=تحويل PDF إلى Word
|
||||||
PDFToWord.header=تحويل PDF إلى Word
|
PDFToWord.header=تحويل PDF إلى Word
|
||||||
PDFToWord.selectText.1=تنسيق ملف الإخراج
|
PDFToWord.selectText.1=تنسيق ملف الإخراج
|
||||||
PDFToWord.credit=تستخدم هذه الخدمة LibreOffice لتحويل الملفات.
|
PDFToWord.credit=تستخدم هذه الخدمة LibreOffice لتحويل الملفات.
|
||||||
PDFToWord.submit=تحويل
|
PDFToWord.submit=تحويل
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDF للعرض التقديمي
|
PDFToPresentation.title=PDF للعرض التقديمي
|
||||||
PDFToPresentation.header=PDF للعرض التقديمي
|
PDFToPresentation.header=PDF للعرض التقديمي
|
||||||
PDFToPresentation.selectText.1=تنسيق ملف الإخراج
|
PDFToPresentation.selectText.1=تنسيق ملف الإخراج
|
||||||
@@ -453,6 +772,7 @@ PDFToPresentation.credit=تستخدم هذه الخدمة LibreOffice لتحوي
|
|||||||
PDFToPresentation.submit=تحويل
|
PDFToPresentation.submit=تحويل
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
PDFToText.title=تحويل PDF إلى نص / RTF
|
PDFToText.title=تحويل PDF إلى نص / RTF
|
||||||
PDFToText.header=تحويل PDF إلى نص / RTF
|
PDFToText.header=تحويل PDF إلى نص / RTF
|
||||||
PDFToText.selectText.1=تنسيق ملف الإخراج
|
PDFToText.selectText.1=تنسيق ملف الإخراج
|
||||||
@@ -460,11 +780,14 @@ PDFToText.credit=تستخدم هذه الخدمة LibreOffice لتحويل ال
|
|||||||
PDFToText.submit=تحويل
|
PDFToText.submit=تحويل
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDF إلى HTML
|
PDFToHTML.title=PDF إلى HTML
|
||||||
PDFToHTML.header=PDF إلى HTML
|
PDFToHTML.header=PDF إلى HTML
|
||||||
PDFToHTML.credit=تستخدم هذه الخدمة LibreOffice لتحويل الملفات.
|
PDFToHTML.credit=تستخدم هذه الخدمة LibreOffice لتحويل الملفات.
|
||||||
PDFToHTML.submit=تحويل
|
PDFToHTML.submit=تحويل
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=تحويل PDF إلى XML
|
PDFToXML.title=تحويل PDF إلى XML
|
||||||
PDFToXML.header=تحويل PDF إلى XML
|
PDFToXML.header=تحويل PDF إلى XML
|
||||||
PDFToXML.credit=تستخدم هذه الخدمة LibreOffice لتحويل الملفات.
|
PDFToXML.credit=تستخدم هذه الخدمة LibreOffice لتحويل الملفات.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=Selecciona PDF(s)
|
pdfPrompt=Selecciona PDF(s)
|
||||||
@@ -21,139 +21,449 @@ filesSelected=fitxers seleccionats
|
|||||||
noFavourites=No s'ha afegit cap favorit
|
noFavourites=No s'ha afegit cap favorit
|
||||||
bored=Avorrit esperant?
|
bored=Avorrit esperant?
|
||||||
alphabet=Alfabet
|
alphabet=Alfabet
|
||||||
|
downloadPdf=Descarregueu PDF
|
||||||
|
text=Text
|
||||||
|
font=Tipus de lletra
|
||||||
|
selectFillter=-- Selecciona --
|
||||||
|
pageNum=Número de pàgina
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
|
navbar.convert=Converteix
|
||||||
|
navbar.security=Seguretat
|
||||||
|
navbar.other=Altres
|
||||||
|
navbar.darkmode=Mode Fost
|
||||||
|
navbar.pageOps=Operacions de Pàgina
|
||||||
|
navbar.settings=Opcions
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=Opcions
|
||||||
|
settings.update=Actualització Disponible
|
||||||
|
settings.appVersion=Versió App:
|
||||||
|
settings.downloadOption.title=Trieu l'opció de descàrrega (per a descàrregues d'un sol fitxer no zip):
|
||||||
|
settings.downloadOption.1=Obre mateixa finestra
|
||||||
|
settings.downloadOption.2=Obre mateixa finestra
|
||||||
|
settings.downloadOption.3=Descarrega Arxiu
|
||||||
|
settings.zipThreshold=Comprimiu els fitxers quan el nombre de fitxers baixats superi
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
#############
|
#############
|
||||||
home.desc=L'eina allotjada localment per a necessitats PDF.
|
home.desc=L'eina allotjada localment per a necessitats PDF.
|
||||||
|
|
||||||
|
|
||||||
navbar.convert=Converteix
|
|
||||||
navbar.security=Seguretat
|
|
||||||
navbar.other=Altres
|
|
||||||
navbar.darkmode=Mode Fost
|
|
||||||
navbar.pageOps=Operacions de Pàgina
|
|
||||||
|
|
||||||
home.multiTool.title=PDF Multi Tool
|
home.multiTool.title=PDF Multi Tool
|
||||||
home.multiTool.desc=Fusiona, Rota, Reorganitza, i Esborra pàgines
|
home.multiTool.desc=Fusiona, Rota, Reorganitza, i Esborra pàgines
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
||||||
|
|
||||||
home.merge.title=Fusiona
|
home.merge.title=Fusiona
|
||||||
home.merge.desc=Fusiona fàcilment pàgines en una.
|
home.merge.desc=Fusiona fàcilment pàgines en una.
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
home.split.title=Divideix
|
home.split.title=Divideix
|
||||||
home.split.desc=Divideix PDFs en múltiples documents
|
home.split.desc=Divideix PDFs en múltiples documents
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
home.rotate.title=Rota
|
home.rotate.title=Rota
|
||||||
home.rotate.desc=Rota els PDFs.
|
home.rotate.desc=Rota els PDFs.
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=Imatge a PDF
|
home.imageToPdf.title=Imatge a PDF
|
||||||
home.imageToPdf.desc=Converteix imatge (PNG, JPEG, GIF) a PDF.
|
home.imageToPdf.desc=Converteix imatge (PNG, JPEG, GIF) a PDF.
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfToImage.title=PDF a Imatge
|
home.pdfToImage.title=PDF a Imatge
|
||||||
home.pdfToImage.desc=Converteix PDF a imatge. (PNG, JPEG, GIF)
|
home.pdfToImage.desc=Converteix PDF a imatge. (PNG, JPEG, GIF)
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfOrganiser.title=Organitza
|
home.pdfOrganiser.title=Organitza
|
||||||
home.pdfOrganiser.desc=Elimina/Reorganitza pàgines en qualsevol ordre
|
home.pdfOrganiser.desc=Elimina/Reorganitza pàgines en qualsevol ordre
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=Afegir imatge a PDF
|
home.addImage.title=Afegir imatge a PDF
|
||||||
home.addImage.desc=Afegeix imatge en un PDF (En progrés)
|
home.addImage.desc=Afegeix imatge en un PDF (En progrés)
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
home.watermark.title=Afegir Marca d'aigua
|
home.watermark.title=Afegir Marca d'aigua
|
||||||
home.watermark.desc=Afegir Marca d'aigua personalitzada en un PDF
|
home.watermark.desc=Afegir Marca d'aigua personalitzada en un PDF
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
home.remove-watermark.title=Treure Marca d'Aigua
|
|
||||||
home.remove-watermark.desc=Treu Marca d'Aigua d'un PDF
|
|
||||||
|
|
||||||
home.permissions.title=Canvia permissos
|
home.permissions.title=Canvia permissos
|
||||||
home.permissions.desc=Canvia permisos del document PDF
|
home.permissions.desc=Canvia permisos del document PDF
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=Elimina
|
home.removePages.title=Elimina
|
||||||
home.removePages.desc=Elimina pàgines del document PDF.
|
home.removePages.desc=Elimina pàgines del document PDF.
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
home.addPassword.title=Afegir Password
|
home.addPassword.title=Afegir Password
|
||||||
home.addPassword.desc=Xifra document PDF amb password.
|
home.addPassword.desc=Xifra document PDF amb password.
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
home.removePassword.title=Elimina Password
|
home.removePassword.title=Elimina Password
|
||||||
home.removePassword.desc=Elimia Password de document PDF.
|
home.removePassword.desc=Elimia Password de document PDF.
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
home.compressPdfs.title=Comprimeix
|
home.compressPdfs.title=Comprimeix
|
||||||
home.compressPdfs.desc=Comprimeix PDFs per reduir la mida.
|
home.compressPdfs.desc=Comprimeix PDFs per reduir la mida.
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=Canvia Metadades
|
home.changeMetadata.title=Canvia Metadades
|
||||||
home.changeMetadata.desc=Canvia/Treu/Afegeix matadades al document PDF.
|
home.changeMetadata.desc=Canvia/Treu/Afegeix matadades al document PDF.
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Converteix arxiu a PDF
|
home.fileToPDF.title=Converteix arxiu a PDF
|
||||||
home.fileToPDF.desc=Converteix qualsevol arxiu a PDF (DOCX, PNG, XLS, PPT, TXT i més)
|
home.fileToPDF.desc=Converteix qualsevol arxiu a PDF (DOCX, PNG, XLS, PPT, TXT i més)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=Executa exploracions OCR i/o neteja escanejos
|
home.ocr.title=Executa exploracions OCR i/o neteja escanejos
|
||||||
home.ocr.desc=Neteja escanejats i detecta text d'imatges dins d'un PDF i el torna a afegir com a text.
|
home.ocr.desc=Neteja escanejats i detecta text d'imatges dins d'un PDF i el torna a afegir com a text.
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
home.extractImages.title=Extreu Imatges
|
home.extractImages.title=Extreu Imatges
|
||||||
home.extractImages.desc=Extreu les Imatges del PDF i les desa a zip
|
home.extractImages.desc=Extreu les Imatges del PDF i les desa a zip
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
home.pdfToPDFA.title=PDF a PDF/A
|
home.pdfToPDFA.title=PDF a PDF/A
|
||||||
home.pdfToPDFA.desc=Converteix PDF a PDF/A per desar a llarg termini.
|
home.pdfToPDFA.desc=Converteix PDF a PDF/A per desar a llarg termini.
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
home.PDFToWord.title=PDF a Word
|
home.PDFToWord.title=PDF a Word
|
||||||
home.PDFToWord.desc=Converteix PDF a formats de Word (DOC, DOCX and ODT)
|
home.PDFToWord.desc=Converteix PDF a formats de Word (DOC, DOCX and ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDF a Presentació
|
home.PDFToPresentation.title=PDF a Presentació
|
||||||
home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP)
|
home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=PDF a Text/RTF
|
home.PDFToText.title=PDF a Text/RTF
|
||||||
home.PDFToText.desc=Converteix PDF a Text o format RTF
|
home.PDFToText.desc=Converteix PDF a Text o format RTF
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
home.PDFToHTML.title=PDF a HTML
|
home.PDFToHTML.title=PDF a HTML
|
||||||
home.PDFToHTML.desc=Converteix PDF a format HTML
|
home.PDFToHTML.desc=Converteix PDF a format HTML
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=PDF a XML
|
home.PDFToXML.title=PDF a XML
|
||||||
home.PDFToXML.desc=Converteix PDF a format XML
|
home.PDFToXML.desc=Converteix PDF a format XML
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
home.ScannerImageSplit.title=Detecta/Divideix fotos escanejades
|
home.ScannerImageSplit.title=Detecta/Divideix fotos escanejades
|
||||||
home.ScannerImageSplit.desc=Divideix múltiples fotos dins del PDF/foto
|
home.ScannerImageSplit.desc=Divideix múltiples fotos dins del PDF/foto
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
home.sign.title=Sign
|
home.sign.title=Sign
|
||||||
home.sign.desc=Afegeix signatura al PDF mitjançant dibuix, text o imatge
|
home.sign.desc=Afegeix signatura al PDF mitjançant dibuix, text o imatge
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
home.flatten.title=Aplanar
|
home.flatten.title=Aplanar
|
||||||
home.flatten.desc=Elimineu tots els elements i formularis interactius d'un PDF
|
home.flatten.desc=Elimineu tots els elements i formularis interactius d'un PDF
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
home.repair.title=Reparar
|
home.repair.title=Reparar
|
||||||
home.repair.desc=Intenta reparar un PDF danyat o trencat
|
home.repair.desc=Intenta reparar un PDF danyat o trencat
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
home.removeBlanks.title=Elimina les pàgines en blanc
|
home.removeBlanks.title=Elimina les pàgines en blanc
|
||||||
home.removeBlanks.desc=Detecta i elimina les pàgines en blanc d'un document
|
home.removeBlanks.desc=Detecta i elimina les pàgines en blanc d'un document
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
home.certSign.title=Sign with Certificate
|
|
||||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
|
||||||
|
|
||||||
home.compare.title=Compara
|
home.compare.title=Compara
|
||||||
home.compare.desc=Compara i mostra les diferències entre 2 documents PDF
|
home.compare.desc=Compara i mostra les diferències entre 2 documents PDF
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
|
home.certSign.title=Sign with Certificate
|
||||||
|
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
home.pageLayout.title=Multi-Page Layout
|
home.pageLayout.title=Multi-Page Layout
|
||||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
home.scalePages.title=Adjust page size/scale
|
home.scalePages.title=Adjust page size/scale
|
||||||
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
downloadPdf=Descarregueu PDF
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
text=Text
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
font=Tipus de lletra
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
selectFillter=-- Selecciona --
|
|
||||||
pageNum=Número de pàgina
|
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Multi Page Layout
|
pageLayout.title=Multi Page Layout
|
||||||
pageLayout.header=Multi Page Layout
|
pageLayout.header=Multi Page Layout
|
||||||
pageLayout.pagesPerSheet=Pages per sheet:
|
pageLayout.pagesPerSheet=Pages per sheet:
|
||||||
pageLayout.submit=Submit
|
pageLayout.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Adjust page-scale
|
scalePages.title=Adjust page-scale
|
||||||
scalePages.header=Adjust page-scale
|
scalePages.header=Adjust page-scale
|
||||||
scalePages.pageSize=Size of a page of the document.
|
scalePages.pageSize=Size of a page of the document.
|
||||||
scalePages.scaleFactor=Zoom level (crop) of a page.
|
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||||
scalePages.submit=Submit
|
scalePages.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=Significació del certificat
|
certSign.title=Significació del certificat
|
||||||
certSign.header=Firmar un PDF amb el vostre certificat (Treball en curs)
|
certSign.header=Firmar un PDF amb el vostre certificat (Treball en curs)
|
||||||
certSign.selectPDF=Seleccioneu un fitxer PDF per signar:
|
certSign.selectPDF=Seleccioneu un fitxer PDF per signar:
|
||||||
@@ -168,6 +478,8 @@ certSign.location=Ubicació
|
|||||||
certSign.name=Nom
|
certSign.name=Nom
|
||||||
certSign.submit=Firma PDF
|
certSign.submit=Firma PDF
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=Elimina els espais en blanc
|
removeBlanks.title=Elimina els espais en blanc
|
||||||
removeBlanks.header=Elimina les pàgines en blanc
|
removeBlanks.header=Elimina les pàgines en blanc
|
||||||
removeBlanks.threshold=Llindar:
|
removeBlanks.threshold=Llindar:
|
||||||
@@ -176,12 +488,16 @@ removeBlanks.whitePercent=Percentatge blanc (%):
|
|||||||
removeBlanks.whitePercentDesc=Percentatge de pàgina que ha de ser blanca per eliminar-la
|
removeBlanks.whitePercentDesc=Percentatge de pàgina que ha de ser blanca per eliminar-la
|
||||||
removeBlanks.submit=Elimina els espais en blanc
|
removeBlanks.submit=Elimina els espais en blanc
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=Comparar
|
compare.title=Comparar
|
||||||
compare.header=Compara PDF
|
compare.header=Compara PDF
|
||||||
compare.document.1=Document 1
|
compare.document.1=Document 1
|
||||||
compare.document.2=Document 2
|
compare.document.2=Document 2
|
||||||
compare.submit=Comparar
|
compare.submit=Comparar
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=Sign
|
sign.title=Sign
|
||||||
sign.header=Firma els PDF
|
sign.header=Firma els PDF
|
||||||
sign.upload=Penja la imatge
|
sign.upload=Penja la imatge
|
||||||
@@ -190,14 +506,20 @@ sign.text=Entrada de text
|
|||||||
sign.clear=Esborrar
|
sign.clear=Esborrar
|
||||||
sign.add=Afegeix
|
sign.add=Afegeix
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
repair.header=Repara els PDF
|
repair.header=Repara els PDF
|
||||||
repair.submit=Reparar
|
repair.submit=Reparar
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=Aplanar
|
flatten.title=Aplanar
|
||||||
flatten.header=Aplana els PDF
|
flatten.header=Aplana els PDF
|
||||||
flatten.submit=Aplanar
|
flatten.submit=Aplanar
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=Llindar d'angle:
|
ScannerImageSplit.selectText.1=Llindar d'angle:
|
||||||
ScannerImageSplit.selectText.2=Estableix l'angle absolut mínim necessari perquè la imatge es giri (per defecte: 10).
|
ScannerImageSplit.selectText.2=Estableix l'angle absolut mínim necessari perquè la imatge es giri (per defecte: 10).
|
||||||
ScannerImageSplit.selectText.3=Tolerància:
|
ScannerImageSplit.selectText.3=Tolerància:
|
||||||
@@ -209,19 +531,6 @@ ScannerImageSplit.selectText.8=Estableix el llindar mínim de l'àrea de contorn
|
|||||||
ScannerImageSplit.selectText.9=Mida Vora:
|
ScannerImageSplit.selectText.9=Mida Vora:
|
||||||
ScannerImageSplit.selectText.10=Estableix la mida de la vora afegida i eliminada per evitar vores blanques a la sortida (per defecte: 1).
|
ScannerImageSplit.selectText.10=Estableix la mida de la vora afegida i eliminada per evitar vores blanques a la sortida (per defecte: 1).
|
||||||
|
|
||||||
navbar.settings=Opcions
|
|
||||||
settings.title=Opcions
|
|
||||||
settings.update=Actualització Disponible
|
|
||||||
settings.appVersion=Versió App:
|
|
||||||
settings.downloadOption.title=Trieu l'opció de descàrrega (per a descàrregues d'un sol fitxer no zip):
|
|
||||||
settings.downloadOption.1=Obre mateixa finestra
|
|
||||||
settings.downloadOption.2=Obre mateixa finestra
|
|
||||||
settings.downloadOption.3=Descarrega Arxiu
|
|
||||||
settings.zipThreshold=Comprimiu els fitxers quan el nombre de fitxers baixats superi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / Neteja escaneig
|
ocr.title=OCR / Neteja escaneig
|
||||||
@@ -243,7 +552,7 @@ ocr.credit=Aquest servei empra OCRmyPDF i Tesseract per OCR.
|
|||||||
ocr.submit=Processa PDF amb OCR
|
ocr.submit=Processa PDF amb OCR
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=Extreu Imatges
|
extractImages.title=Extreu Imatges
|
||||||
extractImages.header=Extreu Imatges
|
extractImages.header=Extreu Imatges
|
||||||
extractImages.selectText=Selecciona el format d'imatge al qual convertir les imatges extretes
|
extractImages.selectText=Selecciona el format d'imatge al qual convertir les imatges extretes
|
||||||
@@ -269,6 +578,7 @@ compress.selectText.4=Mode automàtic: ajusta automàticament la qualitat per ta
|
|||||||
compress.selectText.5=Mida esperada del PDF (p. ex. 25 MB, 10,8 MB, 25 KB)
|
compress.selectText.5=Mida esperada del PDF (p. ex. 25 MB, 10,8 MB, 25 KB)
|
||||||
compress.submit=Comprimir
|
compress.submit=Comprimir
|
||||||
|
|
||||||
|
|
||||||
#Add image
|
#Add image
|
||||||
addImage.title=Afegir Imatge
|
addImage.title=Afegir Imatge
|
||||||
addImage.header=Afegir Imatge a PDF (en construcció)
|
addImage.header=Afegir Imatge a PDF (en construcció)
|
||||||
@@ -280,13 +590,17 @@ addImage.submit=Afegir Imatge
|
|||||||
#merge
|
#merge
|
||||||
merge.title=Fusiona
|
merge.title=Fusiona
|
||||||
merge.header=Fusiona múltiples PDFs (2+)
|
merge.header=Fusiona múltiples PDFs (2+)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=Fusiona
|
merge.submit=Fusiona
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=Organitzador de pàgines
|
pdfOrganiser.title=Organitzador de pàgines
|
||||||
pdfOrganiser.header=Organitzador de pàgines PDF
|
pdfOrganiser.header=Organitzador de pàgines PDF
|
||||||
pdfOrganiser.submit=Reorganitza Pàgines
|
pdfOrganiser.submit=Reorganitza Pàgines
|
||||||
|
|
||||||
|
|
||||||
#multiTool
|
#multiTool
|
||||||
multiTool.title=PDF Multi Tool
|
multiTool.title=PDF Multi Tool
|
||||||
multiTool.header=PDF Multi Tool
|
multiTool.header=PDF Multi Tool
|
||||||
@@ -298,6 +612,7 @@ pageRemover.header=Eliminació Pàgines PDF
|
|||||||
pageRemover.pagesToDelete=Pàgines a esborrar (Números de pàgina) :
|
pageRemover.pagesToDelete=Pàgines a esborrar (Números de pàgina) :
|
||||||
pageRemover.submit=Esborra Pàgines
|
pageRemover.submit=Esborra Pàgines
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=Rota PDF
|
rotate.title=Rota PDF
|
||||||
rotate.header=Rota PDF
|
rotate.header=Rota PDF
|
||||||
@@ -305,8 +620,6 @@ rotate.selectAngle=Selecciona l'angle de gir (en múltiples de 90 graus):
|
|||||||
rotate.submit=Rota
|
rotate.submit=Rota
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=Divideix PDF
|
split.title=Divideix PDF
|
||||||
split.header=Divideix PDF
|
split.header=Divideix PDF
|
||||||
@@ -332,6 +645,7 @@ imageToPDF.selectText.3=Lògica de diversos fitxers (només està activada si es
|
|||||||
imageToPDF.selectText.4=Combina en un únic PDF
|
imageToPDF.selectText.4=Combina en un únic PDF
|
||||||
imageToPDF.selectText.5=Converteix per separar PDFs
|
imageToPDF.selectText.5=Converteix per separar PDFs
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDF a Imatge
|
pdfToImage.title=PDF a Imatge
|
||||||
pdfToImage.header=PDF a Imatge
|
pdfToImage.header=PDF a Imatge
|
||||||
@@ -345,6 +659,7 @@ pdfToImage.grey=Escala de Grisos
|
|||||||
pdfToImage.blackwhite=Blanc i Negre (Pot perdre dades!)
|
pdfToImage.blackwhite=Blanc i Negre (Pot perdre dades!)
|
||||||
pdfToImage.submit=Converteix
|
pdfToImage.submit=Converteix
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=Afegir Password
|
addPassword.title=Afegir Password
|
||||||
addPassword.header=Afegir password (Encriptat)
|
addPassword.header=Afegir password (Encriptat)
|
||||||
@@ -366,6 +681,7 @@ addPassword.selectText.15=Restricts what can be done with the document once it i
|
|||||||
addPassword.selectText.16=Restricts the opening of the document itself
|
addPassword.selectText.16=Restricts the opening of the document itself
|
||||||
addPassword.submit=Encripta
|
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
|
||||||
@@ -376,14 +692,10 @@ watermark.selectText.4=Rotació (0-360):
|
|||||||
watermark.selectText.5=separació d'amplada (Espai horitzontal entre cada Marca d'Aigua):
|
watermark.selectText.5=separació d'amplada (Espai horitzontal entre cada Marca d'Aigua):
|
||||||
watermark.selectText.6=separació d'alçada (Espai vertical entre cada Marca d'Aigua):
|
watermark.selectText.6=separació d'alçada (Espai vertical entre cada Marca d'Aigua):
|
||||||
watermark.selectText.7=Opacitat (0% - 100%):
|
watermark.selectText.7=Opacitat (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=Afegir Marca d'Aigua
|
watermark.submit=Afegir Marca d'Aigua
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=Elimina Marca d'Aigua
|
|
||||||
remove-watermark.header=Elimina Marca d'Aigua
|
|
||||||
remove-watermark.selectText.1=Seleciona PDF per eliminar Marca d'Aigua:
|
|
||||||
remove-watermark.selectText.2=Text de la Marca d'Aigua:
|
|
||||||
remove-watermark.submit=Elimina Marca d'Aigua
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=Canviar Permissos
|
permissions.title=Canviar Permissos
|
||||||
@@ -401,6 +713,7 @@ permissions.selectText.9=Evita impressió
|
|||||||
permissions.selectText.10=Evita impressió de diferents formats
|
permissions.selectText.10=Evita impressió de diferents formats
|
||||||
permissions.submit=Canviar Permissos
|
permissions.submit=Canviar Permissos
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=Treure Password
|
removePassword.title=Treure Password
|
||||||
removePassword.header=Treure Password (Decriptar)
|
removePassword.header=Treure Password (Decriptar)
|
||||||
@@ -408,7 +721,9 @@ removePassword.selectText.1=Selecciona PDF a Decriptar
|
|||||||
removePassword.selectText.2=Password
|
removePassword.selectText.2=Password
|
||||||
removePassword.submit=Treu Password
|
removePassword.submit=Treu Password
|
||||||
|
|
||||||
changeMetadata.title=Canvia Metadades
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=Títol:
|
||||||
changeMetadata.header=Canvia Metadades
|
changeMetadata.header=Canvia Metadades
|
||||||
changeMetadata.selectText.1=Edit les variables a canviar
|
changeMetadata.selectText.1=Edit les variables a canviar
|
||||||
changeMetadata.selectText.2=Neteja totes les matadades
|
changeMetadata.selectText.2=Neteja totes les matadades
|
||||||
@@ -426,27 +741,30 @@ changeMetadata.selectText.4=Altres Metadades:
|
|||||||
changeMetadata.selectText.5=Afegir entrada personalizada
|
changeMetadata.selectText.5=Afegir entrada personalizada
|
||||||
changeMetadata.submit=Canvia
|
changeMetadata.submit=Canvia
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=Excel a PDF
|
xlsToPdf.title=Excel a PDF
|
||||||
xlsToPdf.header=Excel a PDF
|
xlsToPdf.header=Excel a PDF
|
||||||
xlsToPdf.selectText.1=Selecciona arxiu XLS o XLSX a convertir
|
xlsToPdf.selectText.1=Selecciona arxiu XLS o XLSX a convertir
|
||||||
xlsToPdf.convert=Converteix
|
xlsToPdf.convert=Converteix
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
|
||||||
pdfToPDFA.title=PDF a PDF/A
|
pdfToPDFA.title=PDF a PDF/A
|
||||||
pdfToPDFA.header=PDF a PDF/A
|
pdfToPDFA.header=PDF a PDF/A
|
||||||
pdfToPDFA.credit=Utilitza OCRmyPDF per la conversió a PDF/A
|
pdfToPDFA.credit=Utilitza OCRmyPDF per la conversió a PDF/A
|
||||||
pdfToPDFA.submit=Converteix
|
pdfToPDFA.submit=Converteix
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=PDF a Word
|
PDFToWord.title=PDF a Word
|
||||||
PDFToWord.header=PDF a Word
|
PDFToWord.header=PDF a Word
|
||||||
PDFToWord.selectText.1=Format d'Arxiu de Sortida
|
PDFToWord.selectText.1=Format d'Arxiu de Sortida
|
||||||
PDFToWord.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
PDFToWord.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
||||||
PDFToWord.submit=Converteix
|
PDFToWord.submit=Converteix
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDF a Presentació
|
PDFToPresentation.title=PDF a Presentació
|
||||||
PDFToPresentation.header=PDF a Presentació
|
PDFToPresentation.header=PDF a Presentació
|
||||||
PDFToPresentation.selectText.1=Format d'Arxiu de Sortida
|
PDFToPresentation.selectText.1=Format d'Arxiu de Sortida
|
||||||
@@ -454,6 +772,7 @@ PDFToPresentation.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
|||||||
PDFToPresentation.submit=Converteix
|
PDFToPresentation.submit=Converteix
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
PDFToText.title=PDF a Text/RTF
|
PDFToText.title=PDF a Text/RTF
|
||||||
PDFToText.header=PDF a Text/RTF
|
PDFToText.header=PDF a Text/RTF
|
||||||
PDFToText.selectText.1=Format d'Arxiu de Sortida
|
PDFToText.selectText.1=Format d'Arxiu de Sortida
|
||||||
@@ -461,24 +780,15 @@ PDFToText.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
|||||||
PDFToText.submit=Converteix
|
PDFToText.submit=Converteix
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDF a HTML
|
PDFToHTML.title=PDF a HTML
|
||||||
PDFToHTML.header=PDF a HTML
|
PDFToHTML.header=PDF a HTML
|
||||||
PDFToHTML.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
PDFToHTML.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
||||||
PDFToHTML.submit=Converteix
|
PDFToHTML.submit=Converteix
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=PDF a XML
|
PDFToXML.title=PDF a XML
|
||||||
PDFToXML.header=PDF a XML
|
PDFToXML.header=PDF a XML
|
||||||
PDFToXML.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
PDFToXML.credit=Utilitza LibreOffice per a la conversió d'Arxius.
|
||||||
PDFToXML.submit=Converteix
|
PDFToXML.submit=Converteix
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr=left to right, rtl=right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=PDF auswählen
|
pdfPrompt=PDF auswählen
|
||||||
@@ -21,138 +21,449 @@ filesSelected=Dateien ausgewählt
|
|||||||
noFavourites=Keine Favoriten hinzugefügt
|
noFavourites=Keine Favoriten hinzugefügt
|
||||||
bored=Gelangweiltes Warten?
|
bored=Gelangweiltes Warten?
|
||||||
alphabet=Alphabet
|
alphabet=Alphabet
|
||||||
#############
|
|
||||||
# HOME-PAGE #
|
|
||||||
#############
|
|
||||||
home.desc=Ihr lokal gehosteter One-Stop-Shop für alle Ihre PDF-Anforderungen.
|
|
||||||
|
|
||||||
navbar.convert=Konvertieren
|
|
||||||
navbar.security=Sicherheit
|
|
||||||
navbar.other=Anderes
|
|
||||||
navbar.darkmode=Dark Mode
|
|
||||||
navbar.pageOps=Seitenoperationen
|
|
||||||
|
|
||||||
home.multiTool.title=PDF-Multitool
|
|
||||||
home.multiTool.desc=Seiten zusammenführen, drehen, neu anordnen und entfernen
|
|
||||||
|
|
||||||
home.merge.title=Zusammenführen
|
|
||||||
home.merge.desc=Mehrere PDF-Dateien zu einer einzigen zusammenführen.
|
|
||||||
|
|
||||||
home.split.title=Aufteilen
|
|
||||||
home.split.desc=PDFs in mehrere Dokumente aufteilen.
|
|
||||||
|
|
||||||
home.rotate.title=Drehen
|
|
||||||
home.rotate.desc=Drehen Sie Ihre PDFs ganz einfach.
|
|
||||||
|
|
||||||
home.imageToPdf.title=Bild zu PDF
|
|
||||||
home.imageToPdf.desc=Konvertieren Sie ein Bild (PNG, JPEG, GIF) in ein PDF.
|
|
||||||
|
|
||||||
home.pdfToImage.title=PDF zu Bild
|
|
||||||
home.pdfToImage.desc=Konvertieren Sie ein PDF in ein Bild (PNG, JPEG, GIF).
|
|
||||||
|
|
||||||
home.pdfOrganiser.title=Organisieren
|
|
||||||
home.pdfOrganiser.desc=Seiten entfernen und Seitenreihenfolge ändern.
|
|
||||||
|
|
||||||
home.addImage.title=Bild einfügen
|
|
||||||
home.addImage.desc=Fügt ein Bild an eine bestimmte Stelle im PDF ein (Work in progress).
|
|
||||||
|
|
||||||
home.watermark.title=Wasserzeichen hinzufügen
|
|
||||||
home.watermark.desc=Fügen Sie ein eigenes Wasserzeichen zu Ihrem PDF hinzu.
|
|
||||||
|
|
||||||
home.remove-watermark.title=Wasserzeichen entfernen
|
|
||||||
home.remove-watermark.desc=Wasserzeichen aus Ihrem PDF-Dokument entfernen.
|
|
||||||
|
|
||||||
home.permissions.title=Berechtigungen ändern
|
|
||||||
home.permissions.desc=Die Berechtigungen für Ihr PDF-Dokument verändern.
|
|
||||||
|
|
||||||
home.removePages.title=Entfernen
|
|
||||||
home.removePages.desc=Ungewollte Seiten aus dem PDF entfernen.
|
|
||||||
|
|
||||||
home.addPassword.title=Passwort hinzufügen
|
|
||||||
home.addPassword.desc=Das PDF mit einem Passwort verschlüsseln.
|
|
||||||
|
|
||||||
home.removePassword.title=Passwort entfernen
|
|
||||||
home.removePassword.desc=Den Passwortschutz eines PDFs entfernen.
|
|
||||||
|
|
||||||
home.compressPdfs.title=Komprimieren
|
|
||||||
home.compressPdfs.desc=PDF komprimieren um die Dateigröße zu reduzieren.
|
|
||||||
|
|
||||||
home.changeMetadata.title=Metadaten ändern
|
|
||||||
home.changeMetadata.desc=Ändern/Entfernen/Hinzufügen von Metadaten aus einem PDF-Dokument
|
|
||||||
|
|
||||||
home.fileToPDF.title=Datei in PDF konvertieren
|
|
||||||
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
|
||||||
|
|
||||||
home.ocr.title=Führe OCR auf PDF- und/oder Cleanup-Scans aus
|
|
||||||
home.ocr.desc=Cleanup scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu.
|
|
||||||
|
|
||||||
home.extractImages.title=Bilder extrahieren
|
|
||||||
home.extractImages.desc=Extrahiert alle Bilder aus einer PDF-Datei und speichert sie als Zip-Datei
|
|
||||||
|
|
||||||
home.pdfToPDFA.title=PDF zu PDF/A konvertieren
|
|
||||||
home.pdfToPDFA.desc=PDF zu PDF/A für Langzeitarchivierung konvertieren
|
|
||||||
|
|
||||||
home.PDFToWord.title=PDF zu Word
|
|
||||||
home.PDFToWord.desc=PDF in Word-Formate konvertieren (DOC, DOCX und ODT)
|
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDF zu Präsentation
|
|
||||||
home.PDFToPresentation.desc=PDF in Präsentationsformate konvertieren (PPT, PPTX und ODP)
|
|
||||||
|
|
||||||
home.PDFToText.title=PDF in Text/RTF
|
|
||||||
home.PDFToText.desc=PDF in Text- oder RTF-Format konvertieren
|
|
||||||
|
|
||||||
home.PDFToHTML.title=PDF in HTML
|
|
||||||
home.PDFToHTML.desc=PDF in HTML-Format konvertieren
|
|
||||||
|
|
||||||
home.PDFToXML.title=PDF in XML
|
|
||||||
home.PDFToXML.desc=PDF in XML-Format konvertieren
|
|
||||||
|
|
||||||
home.ScannerImageSplit.title=Gescannte Fotos erkennen/aufteilen
|
|
||||||
home.ScannerImageSplit.desc=Teilt mehrere Fotos innerhalb eines Fotos/PDF
|
|
||||||
|
|
||||||
home.sign.title=Signieren
|
|
||||||
home.sign.desc=Fügt PDF-Signaturen durch Zeichnung, Text oder Bild hinzu
|
|
||||||
|
|
||||||
home.flatten.title=Abflachen
|
|
||||||
home.flatten.desc=Alle interaktiven Elemente und Formulare aus einem PDF entfernen
|
|
||||||
|
|
||||||
home.repair.title=Reparatur
|
|
||||||
home.repair.desc=Versucht, ein beschädigtes/kaputtes PDF zu reparieren
|
|
||||||
|
|
||||||
home.removeBlanks.title=Leere Seiten entfernen
|
|
||||||
home.removeBlanks.desc=Erkennt und entfernt leere Seiten aus einem Dokument
|
|
||||||
|
|
||||||
home.certSign.title=Sign with Certificate
|
|
||||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
|
||||||
|
|
||||||
home.compare.title=Vergleichen
|
|
||||||
home.compare.desc=Vergleicht und zeigt die Unterschiede zwischen zwei PDF-Dokumenten an
|
|
||||||
|
|
||||||
home.pageLayout.title=Multi-Page Layout
|
|
||||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
|
||||||
|
|
||||||
home.scalePages.title=Adjust page size/scale
|
|
||||||
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
|
||||||
|
|
||||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
|
||||||
|
|
||||||
downloadPdf=PDF herunterladen
|
downloadPdf=PDF herunterladen
|
||||||
text=Text
|
text=Text
|
||||||
font=Schriftart
|
font=Schriftart
|
||||||
selectFillter=-- Auswählen --
|
selectFillter=-- Auswählen --
|
||||||
pageNum=Seitenzahl
|
pageNum=Seitenzahl
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
|
navbar.convert=Konvertieren
|
||||||
|
navbar.security=Sicherheit
|
||||||
|
navbar.other=Anderes
|
||||||
|
navbar.darkmode=Dark Mode
|
||||||
|
navbar.pageOps=Seitenoperationen
|
||||||
|
navbar.settings=Einstellungen
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=Einstellungen
|
||||||
|
settings.update=Update verfügbar
|
||||||
|
settings.appVersion=App-Version:
|
||||||
|
settings.downloadOption.title=Download-Option wählen (für einzelne Dateien, die keine Zip-Downloads sind):
|
||||||
|
settings.downloadOption.1=Im selben Fenster öffnen
|
||||||
|
settings.downloadOption.2=In neuem Fenster öffnen
|
||||||
|
settings.downloadOption.3=Datei herunterladen
|
||||||
|
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
|
#############
|
||||||
|
# HOME-PAGE #
|
||||||
|
#############
|
||||||
|
home.desc=Ihr lokal gehosteter One-Stop-Shop für alle Ihre PDF-Anforderungen.
|
||||||
|
|
||||||
|
|
||||||
|
home.multiTool.title=PDF-Multitool
|
||||||
|
home.multiTool.desc=Seiten zusammenführen, drehen, neu anordnen und entfernen
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
||||||
|
|
||||||
|
home.merge.title=Zusammenführen
|
||||||
|
home.merge.desc=Mehrere PDF-Dateien zu einer einzigen zusammenführen.
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
|
home.split.title=Aufteilen
|
||||||
|
home.split.desc=PDFs in mehrere Dokumente aufteilen.
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
|
home.rotate.title=Drehen
|
||||||
|
home.rotate.desc=Drehen Sie Ihre PDFs ganz einfach.
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
|
home.imageToPdf.title=Bild zu PDF
|
||||||
|
home.imageToPdf.desc=Konvertieren Sie ein Bild (PNG, JPEG, GIF) in ein PDF.
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.pdfToImage.title=PDF zu Bild
|
||||||
|
home.pdfToImage.desc=Konvertieren Sie ein PDF in ein Bild (PNG, JPEG, GIF).
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.pdfOrganiser.title=Organisieren
|
||||||
|
home.pdfOrganiser.desc=Seiten entfernen und Seitenreihenfolge ändern.
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
|
home.addImage.title=Bild einfügen
|
||||||
|
home.addImage.desc=Fügt ein Bild an eine bestimmte Stelle im PDF ein (Work in progress).
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.watermark.title=Wasserzeichen hinzufügen
|
||||||
|
home.watermark.desc=Fügen Sie ein eigenes Wasserzeichen zu Ihrem PDF hinzu.
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.permissions.title=Berechtigungen ändern
|
||||||
|
home.permissions.desc=Die Berechtigungen für Ihr PDF-Dokument verändern.
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
|
home.removePages.title=Entfernen
|
||||||
|
home.removePages.desc=Ungewollte Seiten aus dem PDF entfernen.
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
|
home.addPassword.title=Passwort hinzufügen
|
||||||
|
home.addPassword.desc=Das PDF mit einem Passwort verschlüsseln.
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
|
home.removePassword.title=Passwort entfernen
|
||||||
|
home.removePassword.desc=Den Passwortschutz eines PDFs entfernen.
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
|
home.compressPdfs.title=Komprimieren
|
||||||
|
home.compressPdfs.desc=PDF komprimieren um die Dateigröße zu reduzieren.
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
|
home.changeMetadata.title=Metadaten ändern
|
||||||
|
home.changeMetadata.desc=Ändern/Entfernen/Hinzufügen von Metadaten aus einem PDF-Dokument
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
|
home.fileToPDF.title=Datei in PDF konvertieren
|
||||||
|
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
|
home.ocr.title=Führe OCR auf PDF- und/oder Cleanup-Scans aus
|
||||||
|
home.ocr.desc=Cleanup scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu.
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
|
home.extractImages.title=Bilder extrahieren
|
||||||
|
home.extractImages.desc=Extrahiert alle Bilder aus einer PDF-Datei und speichert sie als Zip-Datei
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
|
home.pdfToPDFA.title=PDF zu PDF/A konvertieren
|
||||||
|
home.pdfToPDFA.desc=PDF zu PDF/A für Langzeitarchivierung konvertieren
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
|
home.PDFToWord.title=PDF zu Word
|
||||||
|
home.PDFToWord.desc=PDF in Word-Formate konvertieren (DOC, DOCX und ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
|
home.PDFToPresentation.title=PDF zu Präsentation
|
||||||
|
home.PDFToPresentation.desc=PDF in Präsentationsformate konvertieren (PPT, PPTX und ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
|
home.PDFToText.title=PDF in Text/RTF
|
||||||
|
home.PDFToText.desc=PDF in Text- oder RTF-Format konvertieren
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
|
home.PDFToHTML.title=PDF in HTML
|
||||||
|
home.PDFToHTML.desc=PDF in HTML-Format konvertieren
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
|
home.PDFToXML.title=PDF in XML
|
||||||
|
home.PDFToXML.desc=PDF in XML-Format konvertieren
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
|
home.ScannerImageSplit.title=Gescannte Fotos erkennen/aufteilen
|
||||||
|
home.ScannerImageSplit.desc=Teilt mehrere Fotos innerhalb eines Fotos/PDF
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
|
home.sign.title=Signieren
|
||||||
|
home.sign.desc=Fügt PDF-Signaturen durch Zeichnung, Text oder Bild hinzu
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
|
home.flatten.title=Abflachen
|
||||||
|
home.flatten.desc=Alle interaktiven Elemente und Formulare aus einem PDF entfernen
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
|
home.repair.title=Reparatur
|
||||||
|
home.repair.desc=Versucht, ein beschädigtes/kaputtes PDF zu reparieren
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
|
home.removeBlanks.title=Leere Seiten entfernen
|
||||||
|
home.removeBlanks.desc=Erkennt und entfernt leere Seiten aus einem Dokument
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
|
|
||||||
|
home.compare.title=Vergleichen
|
||||||
|
home.compare.desc=Vergleicht und zeigt die Unterschiede zwischen zwei PDF-Dokumenten an
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
|
home.certSign.title=Sign with Certificate
|
||||||
|
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
|
home.pageLayout.title=Multi-Page Layout
|
||||||
|
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
|
home.scalePages.title=Adjust page size/scale
|
||||||
|
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Multi Page Layout
|
pageLayout.title=Multi Page Layout
|
||||||
pageLayout.header=Multi Page Layout
|
pageLayout.header=Multi Page Layout
|
||||||
pageLayout.pagesPerSheet=Pages per sheet:
|
pageLayout.pagesPerSheet=Pages per sheet:
|
||||||
pageLayout.submit=Submit
|
pageLayout.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Adjust page-scale
|
scalePages.title=Adjust page-scale
|
||||||
scalePages.header=Adjust page-scale
|
scalePages.header=Adjust page-scale
|
||||||
scalePages.pageSize=Size of a page of the document.
|
scalePages.pageSize=Size of a page of the document.
|
||||||
scalePages.scaleFactor=Zoom level (crop) of a page.
|
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||||
scalePages.submit=Submit
|
scalePages.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=Zertifikatsignierung
|
certSign.title=Zertifikatsignierung
|
||||||
certSign.header=Signieren Sie ein PDF mit Ihrem Zertifikat (in Arbeit)
|
certSign.header=Signieren Sie ein PDF mit Ihrem Zertifikat (in Arbeit)
|
||||||
certSign.selectPDF=Wählen Sie eine PDF-Datei zum Signieren aus:
|
certSign.selectPDF=Wählen Sie eine PDF-Datei zum Signieren aus:
|
||||||
@@ -167,6 +478,8 @@ certSign.location=Standort
|
|||||||
certSign.name=Name
|
certSign.name=Name
|
||||||
certSign.submit=PDF signieren
|
certSign.submit=PDF signieren
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=Leerzeichen entfernen
|
removeBlanks.title=Leerzeichen entfernen
|
||||||
removeBlanks.header=Leere Seiten entfernen
|
removeBlanks.header=Leere Seiten entfernen
|
||||||
removeBlanks.threshold=Schwellenwert:
|
removeBlanks.threshold=Schwellenwert:
|
||||||
@@ -175,12 +488,16 @@ removeBlanks.whitePercent=Weißprozentsatz (%):
|
|||||||
removeBlanks.whitePercentDesc=Prozentsatz der Seite, die weiß sein muss, um entfernt zu werden
|
removeBlanks.whitePercentDesc=Prozentsatz der Seite, die weiß sein muss, um entfernt zu werden
|
||||||
removeBlanks.submit=Leerzeichen entfernen
|
removeBlanks.submit=Leerzeichen entfernen
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=Vergleichen
|
compare.title=Vergleichen
|
||||||
compare.header=PDFs vergleichen
|
compare.header=PDFs vergleichen
|
||||||
compare.document.1=Dokument 1
|
compare.document.1=Dokument 1
|
||||||
compare.document.2=Dokument 2
|
compare.document.2=Dokument 2
|
||||||
compare.submit=Vergleichen
|
compare.submit=Vergleichen
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=Signieren
|
sign.title=Signieren
|
||||||
sign.header=PDFs signieren
|
sign.header=PDFs signieren
|
||||||
sign.upload=Bild hochladen
|
sign.upload=Bild hochladen
|
||||||
@@ -189,14 +506,20 @@ sign.text=Texteingabe
|
|||||||
sign.clear=Klar
|
sign.clear=Klar
|
||||||
sign.add=Hinzufügen
|
sign.add=Hinzufügen
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=Reparieren
|
repair.title=Reparieren
|
||||||
Repair.header=PDFs reparieren
|
repair.header=Repair PDFs
|
||||||
repair.submit=Reparieren
|
repair.submit=Reparieren
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=Abflachen
|
flatten.title=Abflachen
|
||||||
flatten.header=PDFs reduzieren
|
flatten.header=PDFs reduzieren
|
||||||
flatten.submit=Abflachen
|
flatten.submit=Abflachen
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=Winkelschwelle:
|
ScannerImageSplit.selectText.1=Winkelschwelle:
|
||||||
ScannerImageSplit.selectText.2=Legt den minimalen absoluten Winkel fest, der erforderlich ist, damit das Bild gedreht werden kann (Standard: 10).
|
ScannerImageSplit.selectText.2=Legt den minimalen absoluten Winkel fest, der erforderlich ist, damit das Bild gedreht werden kann (Standard: 10).
|
||||||
ScannerImageSplit.selectText.3=Toleranz:
|
ScannerImageSplit.selectText.3=Toleranz:
|
||||||
@@ -209,16 +532,6 @@ ScannerImageSplit.selectText.9=Randgröße:
|
|||||||
ScannerImageSplit.selectText.10=Legt die Größe des hinzugefügten und entfernten Randes fest, um weiße Ränder in der Ausgabe zu verhindern (Standard: 1).
|
ScannerImageSplit.selectText.10=Legt die Größe des hinzugefügten und entfernten Randes fest, um weiße Ränder in der Ausgabe zu verhindern (Standard: 1).
|
||||||
|
|
||||||
|
|
||||||
navbar.settings=Einstellungen
|
|
||||||
settings.title=Einstellungen
|
|
||||||
settings.update=Update verfügbar
|
|
||||||
settings.appVersion=App-Version:
|
|
||||||
settings.downloadOption.title=Download-Option wählen (für einzelne Dateien, die keine Zip-Downloads sind):
|
|
||||||
settings.downloadOption.1=Im selben Fenster öffnen
|
|
||||||
settings.downloadOption.2=In neuem Fenster öffnen
|
|
||||||
settings.downloadOption.3=Datei herunterladen
|
|
||||||
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / Scan-Bereinigung
|
ocr.title=OCR / Scan-Bereinigung
|
||||||
ocr.header=Scans bereinigen / OCR (Optical Character Recognition)
|
ocr.header=Scans bereinigen / OCR (Optical Character Recognition)
|
||||||
@@ -239,6 +552,7 @@ ocr.credit=Dieser Dienst verwendet OCRmyPDF und Tesseract für OCR.
|
|||||||
ocr.submit=PDF mit OCR verarbeiten
|
ocr.submit=PDF mit OCR verarbeiten
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=Bilder extrahieren
|
extractImages.title=Bilder extrahieren
|
||||||
extractImages.header=Bilder extrahieren
|
extractImages.header=Bilder extrahieren
|
||||||
extractImages.selectText=Wählen Sie das Bildformat aus, in das extrahierte Bilder konvertiert werden sollen
|
extractImages.selectText=Wählen Sie das Bildformat aus, in das extrahierte Bilder konvertiert werden sollen
|
||||||
@@ -253,16 +567,6 @@ fileToPDF.supportedFileTypes=Unterstützte Dateitypen sollten die folgenden enth
|
|||||||
fileToPDF.submit=In PDF konvertieren
|
fileToPDF.submit=In PDF konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#Add image
|
|
||||||
addImage.title=Bild hinzufügen
|
|
||||||
addImage.header=Ein Bild einfügen
|
|
||||||
addImage.everyPage=Jede Seite?
|
|
||||||
addImage.upload=Bild hinzufügen
|
|
||||||
addImage.submit=Bild hinzufügen
|
|
||||||
|
|
||||||
#compress
|
#compress
|
||||||
compress.title=Komprimieren
|
compress.title=Komprimieren
|
||||||
compress.header=PDF komprimieren
|
compress.header=PDF komprimieren
|
||||||
@@ -275,26 +579,40 @@ compress.selectText.5=Erwartete PDF-Größe (z. B. 25 MB, 10,8 MB, 25 KB)
|
|||||||
compress.submit=Komprimieren
|
compress.submit=Komprimieren
|
||||||
|
|
||||||
|
|
||||||
|
#Add image
|
||||||
|
addImage.title=Bild hinzufügen
|
||||||
|
addImage.header=Ein Bild einfügen
|
||||||
|
addImage.everyPage=Jede Seite?
|
||||||
|
addImage.upload=Bild hinzufügen
|
||||||
|
addImage.submit=Bild hinzufügen
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
merge.title=Zusammenführen
|
merge.title=Zusammenführen
|
||||||
merge.header=Mehrere PDFs zusammenführen (2+)
|
merge.header=Mehrere PDFs zusammenführen (2+)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=Zusammenführen
|
merge.submit=Zusammenführen
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=Seiten anordnen
|
pdfOrganiser.title=Seiten anordnen
|
||||||
pdfOrganiser.header=PDF Seitenorganisation
|
pdfOrganiser.header=PDF Seitenorganisation
|
||||||
pdfOrganiser.submit=Seiten anordnen
|
pdfOrganiser.submit=Seiten anordnen
|
||||||
|
|
||||||
#Mehrfachwerkzeug
|
|
||||||
|
#multiTool
|
||||||
multiTool.title=PDF-Multitool
|
multiTool.title=PDF-Multitool
|
||||||
multiTool.header=PDF-Multitool
|
multiTool.header=PDF-Multitool
|
||||||
|
|
||||||
|
|
||||||
#pageRemover
|
#pageRemover
|
||||||
pageRemover.title=Seiten entfernen
|
pageRemover.title=Seiten entfernen
|
||||||
pageRemover.header=PDF Seiten entfernen
|
pageRemover.header=PDF Seiten entfernen
|
||||||
pageRemover.pagesToDelete=Seiten zu entfernen (geben Sie eine Kommagetrennte Liste der Seitenzahlen an):
|
pageRemover.pagesToDelete=Seiten zu entfernen (geben Sie eine Kommagetrennte Liste der Seitenzahlen an):
|
||||||
pageRemover.submit=Seiten löschen
|
pageRemover.submit=Seiten löschen
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=PDF drehen
|
rotate.title=PDF drehen
|
||||||
rotate.header=PDF drehen
|
rotate.header=PDF drehen
|
||||||
@@ -302,8 +620,6 @@ rotate.selectAngle=Wählen Sie den Winkel (in Vielfachen von 90 Grad):
|
|||||||
rotate.submit=Drehen
|
rotate.submit=Drehen
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=PDF aufteilen
|
split.title=PDF aufteilen
|
||||||
split.header=PDF aufteilen
|
split.header=PDF aufteilen
|
||||||
@@ -329,6 +645,7 @@ imageToPDF.selectText.3=Mehrere Dateien verarbeiten (nur aktiv, wenn Sie mit meh
|
|||||||
imageToPDF.selectText.4=In ein einziges PDF zusammenführen
|
imageToPDF.selectText.4=In ein einziges PDF zusammenführen
|
||||||
imageToPDF.selectText.5=In separate PDFs konvertieren
|
imageToPDF.selectText.5=In separate PDFs konvertieren
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDF zu Bild
|
pdfToImage.title=PDF zu Bild
|
||||||
pdfToImage.header=PDF zu Bild
|
pdfToImage.header=PDF zu Bild
|
||||||
@@ -342,6 +659,7 @@ pdfToImage.grey=Graustufen
|
|||||||
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
|
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
|
||||||
pdfToImage.submit=Umwandeln
|
pdfToImage.submit=Umwandeln
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=Passwort hinzufügen
|
addPassword.title=Passwort hinzufügen
|
||||||
addPassword.header=Passwort hinzufügen (Verschlüsseln)
|
addPassword.header=Passwort hinzufügen (Verschlüsseln)
|
||||||
@@ -363,6 +681,7 @@ addPassword.selectText.15=Restricts what can be done with the document once it i
|
|||||||
addPassword.selectText.16=Restricts the opening of the document itself
|
addPassword.selectText.16=Restricts the opening of the document itself
|
||||||
addPassword.submit=Verschlüsseln
|
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
|
||||||
@@ -373,14 +692,10 @@ watermark.selectText.4=Drehung (0-360):
|
|||||||
watermark.selectText.5=breiteSpacer (horizontaler Abstand zwischen den einzelnen Wasserzeichen):
|
watermark.selectText.5=breiteSpacer (horizontaler Abstand zwischen den einzelnen Wasserzeichen):
|
||||||
watermark.selectText.6=höheSpacer (vertikaler Abstand zwischen den einzelnen Wasserzeichen):
|
watermark.selectText.6=höheSpacer (vertikaler Abstand zwischen den einzelnen Wasserzeichen):
|
||||||
watermark.selectText.7=Deckkraft (0% - 100 %):
|
watermark.selectText.7=Deckkraft (0% - 100 %):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=Wasserzeichen hinzufügen
|
watermark.submit=Wasserzeichen hinzufügen
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=Wasserzeichen entfernen
|
|
||||||
remove-watermark.header=Wasserzeichen entfernen
|
|
||||||
remove-watermark.selectText.1=PDF auswählen, um Wasserzeichen zu entfernen von:
|
|
||||||
remove-watermark.selectText.2=Wasserzeichentext:
|
|
||||||
remove-watermark.submit=Wasserzeichen entfernen
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=Berechtigungen ändern
|
permissions.title=Berechtigungen ändern
|
||||||
@@ -398,6 +713,7 @@ permissions.selectText.9=Drucken verhindern
|
|||||||
permissions.selectText.10=Drucken verschiedener Formate verhindern
|
permissions.selectText.10=Drucken verschiedener Formate verhindern
|
||||||
permissions.submit=Ändern
|
permissions.submit=Ändern
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=Passwort entfernen
|
removePassword.title=Passwort entfernen
|
||||||
removePassword.header=Passwort entfernen (Entschlüsseln)
|
removePassword.header=Passwort entfernen (Entschlüsseln)
|
||||||
@@ -406,7 +722,8 @@ removePassword.selectText.2=Passwort
|
|||||||
removePassword.submit=Entfernen
|
removePassword.submit=Entfernen
|
||||||
|
|
||||||
|
|
||||||
changeMetadata.title=Metadaten ändern
|
#changeMetadata
|
||||||
|
changeMetadata.title=Titel:
|
||||||
changeMetadata.header=Metadaten ändern
|
changeMetadata.header=Metadaten ändern
|
||||||
changeMetadata.selectText.1=Bitte bearbeiten Sie die Variablen, die Sie ändern möchten
|
changeMetadata.selectText.1=Bitte bearbeiten Sie die Variablen, die Sie ändern möchten
|
||||||
changeMetadata.selectText.2=Alle Metadaten löschen
|
changeMetadata.selectText.2=Alle Metadaten löschen
|
||||||
@@ -425,28 +742,29 @@ changeMetadata.selectText.5=Benutzerdefinierten Metadateneintrag hinzufügen
|
|||||||
changeMetadata.submit=Ändern
|
changeMetadata.submit=Ändern
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=Excel in PDF
|
xlsToPdf.title=Excel in PDF
|
||||||
xlsToPdf.header=Excel in PDF
|
xlsToPdf.header=Excel in PDF
|
||||||
xlsToPdf.selectText.1=XLS- oder XLSX-Excel-Tabelle zum Konvertieren auswählen
|
xlsToPdf.selectText.1=XLS- oder XLSX-Excel-Tabelle zum Konvertieren auswählen
|
||||||
xlsToPdf.convert=konvertieren
|
xlsToPdf.convert=konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
pdfToPDFA.title=PDF zu PDF/A
|
pdfToPDFA.title=PDF zu PDF/A
|
||||||
pdfToPDFA.header=PDF zu PDF/A
|
pdfToPDFA.header=PDF zu PDF/A
|
||||||
pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung
|
pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung
|
||||||
pdfToPDFA.submit=Konvertieren
|
pdfToPDFA.submit=Konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
|
|
||||||
|
|
||||||
PDFToWord.title=PDF zu Word
|
PDFToWord.title=PDF zu Word
|
||||||
PDFToWord.header=PDF zu Word
|
PDFToWord.header=PDF zu Word
|
||||||
PDFToWord.selectText.1=Ausgabedateiformat
|
PDFToWord.selectText.1=Ausgabedateiformat
|
||||||
PDFToWord.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
|
PDFToWord.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
|
||||||
PDFToWord.submit=Konvertieren
|
PDFToWord.submit=Konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDF zu Präsentation
|
PDFToPresentation.title=PDF zu Präsentation
|
||||||
PDFToPresentation.header=PDF zu Präsentation
|
PDFToPresentation.header=PDF zu Präsentation
|
||||||
PDFToPresentation.selectText.1=Ausgabedateiformat
|
PDFToPresentation.selectText.1=Ausgabedateiformat
|
||||||
@@ -454,6 +772,7 @@ PDFToPresentation.credit=Dieser Dienst verwendet LibreOffice für die Dateikonve
|
|||||||
PDFToPresentation.submit=Konvertieren
|
PDFToPresentation.submit=Konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
PDFToText.title=PDF in Text/RTF
|
PDFToText.title=PDF in Text/RTF
|
||||||
PDFToText.header=PDF in Text/RTF
|
PDFToText.header=PDF in Text/RTF
|
||||||
PDFToText.selectText.1=Ausgabedateiformat
|
PDFToText.selectText.1=Ausgabedateiformat
|
||||||
@@ -461,27 +780,15 @@ PDFToText.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung
|
|||||||
PDFToText.submit=Konvertieren
|
PDFToText.submit=Konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDF in HTML
|
PDFToHTML.title=PDF in HTML
|
||||||
PDFToHTML.header=PDF in HTML
|
PDFToHTML.header=PDF in HTML
|
||||||
PDFToHTML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
|
PDFToHTML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
|
||||||
PDFToHTML.submit=Konvertieren
|
PDFToHTML.submit=Konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=PDF in XML
|
PDFToXML.title=PDF in XML
|
||||||
PDFToXML.header=PDF in XML
|
PDFToXML.header=PDF in XML
|
||||||
PDFToXML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
|
PDFToXML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
|
||||||
PDFToXML.submit=Konvertieren
|
PDFToXML.submit=Konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,141 +21,446 @@ filesSelected=files selected
|
|||||||
noFavourites=No favourites added
|
noFavourites=No favourites added
|
||||||
bored=Bored Waiting?
|
bored=Bored Waiting?
|
||||||
alphabet=Alphabet
|
alphabet=Alphabet
|
||||||
|
downloadPdf=Download PDF
|
||||||
|
text=Text
|
||||||
|
font=Font
|
||||||
|
selectFillter=-- Select --
|
||||||
|
pageNum=Page Number
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
|
navbar.convert=Convert
|
||||||
|
navbar.security=Security
|
||||||
|
navbar.other=Other
|
||||||
|
navbar.darkmode=Dark Mode
|
||||||
|
navbar.pageOps=Page Operations
|
||||||
|
navbar.settings=Settings
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=Settings
|
||||||
|
settings.update=Update available
|
||||||
|
settings.appVersion=App Version:
|
||||||
|
settings.downloadOption.title=Choose download option (For single file non zip downloads):
|
||||||
|
settings.downloadOption.1=Open in same window
|
||||||
|
settings.downloadOption.2=Open in new window
|
||||||
|
settings.downloadOption.3=Download file
|
||||||
|
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=New Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
#############
|
#############
|
||||||
home.desc=Your locally hosted one-stop-shop for all your PDF needs.
|
home.desc=Your locally hosted one-stop-shop for all your PDF needs.
|
||||||
|
|
||||||
|
|
||||||
navbar.convert=Convert
|
|
||||||
navbar.security=Security
|
|
||||||
navbar.other=Other
|
|
||||||
navbar.darkmode=Dark Mode
|
|
||||||
navbar.pageOps=Page Operations
|
|
||||||
|
|
||||||
home.multiTool.title=PDF Multi Tool
|
home.multiTool.title=PDF Multi Tool
|
||||||
home.multiTool.desc=Merge, Rotate, Rearrange, and Remove pages
|
home.multiTool.desc=Merge, Rotate, Rearrange, and Remove pages
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side,interactive,intractable,move
|
||||||
|
|
||||||
home.merge.title=Merge
|
home.merge.title=Merge
|
||||||
home.merge.desc=Easily merge multiple PDFs into one.
|
home.merge.desc=Easily merge multiple PDFs into one.
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
home.split.title=Split
|
home.split.title=Split
|
||||||
home.split.desc=Split PDFs into multiple documents
|
home.split.desc=Split PDFs into multiple documents
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
home.rotate.title=Rotate
|
home.rotate.title=Rotate
|
||||||
home.rotate.desc=Easily rotate your PDFs.
|
home.rotate.desc=Easily rotate your PDFs.
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=Image to PDF
|
home.imageToPdf.title=Image to PDF
|
||||||
home.imageToPdf.desc=Convert a image (PNG, JPEG, GIF) to PDF.
|
home.imageToPdf.desc=Convert a image (PNG, JPEG, GIF) to PDF.
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfToImage.title=PDF to Image
|
home.pdfToImage.title=PDF to Image
|
||||||
home.pdfToImage.desc=Convert a PDF to a image. (PNG, JPEG, GIF)
|
home.pdfToImage.desc=Convert a PDF to a image. (PNG, JPEG, GIF)
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfOrganiser.title=Organise
|
home.pdfOrganiser.title=Organise
|
||||||
home.pdfOrganiser.desc=Remove/Rearrange pages in any order
|
home.pdfOrganiser.desc=Remove/Rearrange pages in any order
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=Add image
|
home.addImage.title=Add image
|
||||||
home.addImage.desc=Adds a image onto a set location on the PDF
|
home.addImage.desc=Adds a image onto a set location on the PDF
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
home.watermark.title=Add Watermark
|
home.watermark.title=Add Watermark
|
||||||
home.watermark.desc=Add a custom watermark to your PDF document.
|
home.watermark.desc=Add a custom watermark to your PDF document.
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
|
|
||||||
home.permissions.title=Change Permissions
|
home.permissions.title=Change Permissions
|
||||||
home.permissions.desc=Change the permissions of your PDF document
|
home.permissions.desc=Change the permissions of your PDF document
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=Remove
|
home.removePages.title=Remove
|
||||||
home.removePages.desc=Delete unwanted pages from your PDF document.
|
home.removePages.desc=Delete unwanted pages from your PDF document.
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
home.addPassword.title=Add Password
|
home.addPassword.title=Add Password
|
||||||
home.addPassword.desc=Encrypt your PDF document with a password.
|
home.addPassword.desc=Encrypt your PDF document with a password.
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
home.removePassword.title=Remove Password
|
home.removePassword.title=Remove Password
|
||||||
home.removePassword.desc=Remove password protection from your PDF document.
|
home.removePassword.desc=Remove password protection from your PDF document.
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
home.compressPdfs.title=Compress
|
home.compressPdfs.title=Compress
|
||||||
home.compressPdfs.desc=Compress PDFs to reduce their file size.
|
home.compressPdfs.desc=Compress PDFs to reduce their file size.
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=Change Metadata
|
home.changeMetadata.title=Change Metadata
|
||||||
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Convert file to PDF
|
home.fileToPDF.title=Convert file to PDF
|
||||||
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=OCR / Cleanup scans
|
home.ocr.title=OCR / Cleanup scans
|
||||||
home.ocr.desc=Cleanup scans and detects text from images within a PDF and re-adds it as text.
|
home.ocr.desc=Cleanup scans and detects text from images within a PDF and re-adds it as text.
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
home.extractImages.title=Extract Images
|
home.extractImages.title=Extract Images
|
||||||
home.extractImages.desc=Extracts all images from a PDF and saves them to zip
|
home.extractImages.desc=Extracts all images from a PDF and saves them to zip
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
home.pdfToPDFA.title=PDF to PDF/A
|
home.pdfToPDFA.title=PDF to PDF/A
|
||||||
home.pdfToPDFA.desc=Convert PDF to PDF/A for long-term storage
|
home.pdfToPDFA.desc=Convert PDF to PDF/A for long-term storage
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
home.PDFToWord.title=PDF to Word
|
home.PDFToWord.title=PDF to Word
|
||||||
home.PDFToWord.desc=Convert PDF to Word formats (DOC, DOCX and ODT)
|
home.PDFToWord.desc=Convert PDF to Word formats (DOC, DOCX and ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDF to Presentation
|
home.PDFToPresentation.title=PDF to Presentation
|
||||||
home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP)
|
home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=PDF to Text/RTF
|
home.PDFToText.title=PDF to RTF (Text)
|
||||||
home.PDFToText.desc=Convert PDF to Text or RTF format
|
home.PDFToText.desc=Convert PDF to Text or RTF format
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
home.PDFToHTML.title=PDF to HTML
|
home.PDFToHTML.title=PDF to HTML
|
||||||
home.PDFToHTML.desc=Convert PDF to HTML format
|
home.PDFToHTML.desc=Convert PDF to HTML format
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=PDF to XML
|
home.PDFToXML.title=PDF to XML
|
||||||
home.PDFToXML.desc=Convert PDF to XML format
|
home.PDFToXML.desc=Convert PDF to XML format
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
home.ScannerImageSplit.title=Detect/Split Scanned photos
|
home.ScannerImageSplit.title=Detect/Split Scanned photos
|
||||||
home.ScannerImageSplit.desc=Splits multiple photos from within a photo/PDF
|
home.ScannerImageSplit.desc=Splits multiple photos from within a photo/PDF
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
home.sign.title=Sign
|
home.sign.title=Sign
|
||||||
home.sign.desc=Adds signature to PDF by drawing, text or image
|
home.sign.desc=Adds signature to PDF by drawing, text or image
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
home.flatten.title=Flatten
|
home.flatten.title=Flatten
|
||||||
home.flatten.desc=Remove all interactive elements and forms from a PDF
|
home.flatten.desc=Remove all interactive elements and forms from a PDF
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
home.repair.title=Repair
|
home.repair.title=Repair
|
||||||
home.repair.desc=Tries to repair a corrupt/broken PDF
|
home.repair.desc=Tries to repair a corrupt/broken PDF
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
home.removeBlanks.title=Remove Blank pages
|
home.removeBlanks.title=Remove Blank pages
|
||||||
home.removeBlanks.desc=Detects and removes blank pages from a document
|
home.removeBlanks.desc=Detects and removes blank pages from a document
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
|
|
||||||
home.compare.title=Compare
|
home.compare.title=Compare
|
||||||
home.compare.desc=Compares and shows the differences between 2 PDF Documents
|
home.compare.desc=Compares and shows the differences between 2 PDF Documents
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
home.certSign.title=Sign with Certificate
|
home.certSign.title=Sign with Certificate
|
||||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
home.pageLayout.title=Multi-Page Layout
|
home.pageLayout.title=Multi-Page Layout
|
||||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
home.scalePages.title=Adjust page size/scale
|
home.scalePages.title=Adjust page size/scale
|
||||||
home.scalePages.desc=Change the size/scale of a page and/or its contents.
|
home.scalePages.desc=Change the size/scale of a page and/or its contents.
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
home.pipeline.title=Pipeline
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
home.pipeline.desc=Pipeline desc.
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
|
|
||||||
downloadPdf=Download PDF
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
text=Text
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
font=Font
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
selectFillter=-- Select --
|
|
||||||
pageNum=Page Number
|
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=Redact,Hide,black out,black,marker,hidden
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
pipeline.title=Pipeline
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Multi Page Layout
|
pageLayout.title=Multi Page Layout
|
||||||
pageLayout.header=Multi Page Layout
|
pageLayout.header=Multi Page Layout
|
||||||
pageLayout.pagesPerSheet=Pages per sheet:
|
pageLayout.pagesPerSheet=Pages per sheet:
|
||||||
pageLayout.submit=Submit
|
pageLayout.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Adjust page-scale
|
scalePages.title=Adjust page-scale
|
||||||
scalePages.header=Adjust page-scale
|
scalePages.header=Adjust page-scale
|
||||||
scalePages.pageSize=Size of a page of the document.
|
scalePages.pageSize=Size of a page of the document.
|
||||||
scalePages.scaleFactor=Zoom level (crop) of a page.
|
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||||
scalePages.submit=Submit
|
scalePages.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=Certificate Signing
|
certSign.title=Certificate Signing
|
||||||
certSign.header=Sign a PDF with your certificate (Work in progress)
|
certSign.header=Sign a PDF with your certificate (Work in progress)
|
||||||
certSign.selectPDF=Select a PDF File for Signing:
|
certSign.selectPDF=Select a PDF File for Signing:
|
||||||
@@ -168,25 +473,28 @@ certSign.showSig=Show Signature
|
|||||||
certSign.reason=Reason
|
certSign.reason=Reason
|
||||||
certSign.location=Location
|
certSign.location=Location
|
||||||
certSign.name=Name
|
certSign.name=Name
|
||||||
|
|
||||||
certSign.submit=Sign PDF
|
certSign.submit=Sign PDF
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=Remove Blanks
|
removeBlanks.title=Remove Blanks
|
||||||
removeBlanks.header=Remove Blank Pages
|
removeBlanks.header=Remove Blank Pages
|
||||||
removeBlanks.threshold=Threshold:
|
removeBlanks.threshold=Pixel Whiteness Threshold:
|
||||||
removeBlanks.thresholdDesc=Threshold for determining how white a white pixel must be
|
removeBlanks.thresholdDesc=Threshold for determining how white a white pixel must be to be classed as 'White'. 0 = Black, 255 pure white.
|
||||||
removeBlanks.whitePercent=White Percent (%):
|
removeBlanks.whitePercent=White Percent (%):
|
||||||
removeBlanks.whitePercentDesc=Percent of page that must be white to be removed
|
removeBlanks.whitePercentDesc=Percent of page that must be 'white' pixels to be removed
|
||||||
removeBlanks.submit=Remove Blanks
|
removeBlanks.submit=Remove Blanks
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=Compare
|
compare.title=Compare
|
||||||
compare.header=Compare PDFs
|
compare.header=Compare PDFs
|
||||||
compare.document.1=Document 1
|
compare.document.1=Document 1
|
||||||
compare.document.2=Document 2
|
compare.document.2=Document 2
|
||||||
compare.submit=Compare
|
compare.submit=Compare
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=Sign
|
sign.title=Sign
|
||||||
sign.header=Sign PDFs
|
sign.header=Sign PDFs
|
||||||
sign.upload=Upload Image
|
sign.upload=Upload Image
|
||||||
@@ -195,14 +503,20 @@ sign.text=Text Input
|
|||||||
sign.clear=Clear
|
sign.clear=Clear
|
||||||
sign.add=Add
|
sign.add=Add
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=Repair
|
repair.title=Repair
|
||||||
repair.header=Repair PDFs
|
repair.header=Repair PDFs
|
||||||
repair.submit=Repair
|
repair.submit=Repair
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=Flatten
|
flatten.title=Flatten
|
||||||
flatten.header=Flatten PDFs
|
flatten.header=Flatten PDFs
|
||||||
flatten.submit=Flatten
|
flatten.submit=Flatten
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=Angle Threshold:
|
ScannerImageSplit.selectText.1=Angle Threshold:
|
||||||
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
|
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
|
||||||
ScannerImageSplit.selectText.3=Tolerance:
|
ScannerImageSplit.selectText.3=Tolerance:
|
||||||
@@ -214,19 +528,6 @@ ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a pho
|
|||||||
ScannerImageSplit.selectText.9=Border Size:
|
ScannerImageSplit.selectText.9=Border Size:
|
||||||
ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1).
|
ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1).
|
||||||
|
|
||||||
navbar.settings=Settings
|
|
||||||
settings.title=Settings
|
|
||||||
settings.update=Update available
|
|
||||||
settings.appVersion=App Version:
|
|
||||||
settings.downloadOption.title=Choose download option (For single file non zip downloads):
|
|
||||||
settings.downloadOption.1=Open in same window
|
|
||||||
settings.downloadOption.2=Open in new window
|
|
||||||
settings.downloadOption.3=Download file
|
|
||||||
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / Scan Cleanup
|
ocr.title=OCR / Scan Cleanup
|
||||||
@@ -248,7 +549,7 @@ ocr.credit=This service uses OCRmyPDF and Tesseract for OCR.
|
|||||||
ocr.submit=Process PDF with OCR
|
ocr.submit=Process PDF with OCR
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=Extract Images
|
extractImages.title=Extract Images
|
||||||
extractImages.header=Extract Images
|
extractImages.header=Extract Images
|
||||||
extractImages.selectText=Select image format to convert extracted images to
|
extractImages.selectText=Select image format to convert extracted images to
|
||||||
@@ -286,13 +587,17 @@ addImage.submit=Add image
|
|||||||
#merge
|
#merge
|
||||||
merge.title=Merge
|
merge.title=Merge
|
||||||
merge.header=Merge multiple PDFs (2+)
|
merge.header=Merge multiple PDFs (2+)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=Merge
|
merge.submit=Merge
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=Page Organiser
|
pdfOrganiser.title=Page Organiser
|
||||||
pdfOrganiser.header=PDF Page Organiser
|
pdfOrganiser.header=PDF Page Organiser
|
||||||
pdfOrganiser.submit=Rearrange Pages
|
pdfOrganiser.submit=Rearrange Pages
|
||||||
|
|
||||||
|
|
||||||
#multiTool
|
#multiTool
|
||||||
multiTool.title=PDF Multi Tool
|
multiTool.title=PDF Multi Tool
|
||||||
multiTool.header=PDF Multi Tool
|
multiTool.header=PDF Multi Tool
|
||||||
@@ -304,6 +609,7 @@ pageRemover.header=PDF Page remover
|
|||||||
pageRemover.pagesToDelete=Pages to delete (Enter a comma-separated list of page numbers) :
|
pageRemover.pagesToDelete=Pages to delete (Enter a comma-separated list of page numbers) :
|
||||||
pageRemover.submit=Delete Pages
|
pageRemover.submit=Delete Pages
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=Rotate PDF
|
rotate.title=Rotate PDF
|
||||||
rotate.header=Rotate PDF
|
rotate.header=Rotate PDF
|
||||||
@@ -311,8 +617,6 @@ rotate.selectAngle=Select rotation angle (in multiples of 90 degrees):
|
|||||||
rotate.submit=Rotate
|
rotate.submit=Rotate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=Split PDF
|
split.title=Split PDF
|
||||||
split.header=Split PDF
|
split.header=Split PDF
|
||||||
@@ -338,19 +642,21 @@ imageToPDF.selectText.3=Multi file logic (Only enabled if working with multiple
|
|||||||
imageToPDF.selectText.4=Merge into single PDF
|
imageToPDF.selectText.4=Merge into single PDF
|
||||||
imageToPDF.selectText.5=Convert to separate PDFs
|
imageToPDF.selectText.5=Convert to separate PDFs
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDF to Image
|
pdfToImage.title=PDF to Image
|
||||||
pdfToImage.header=PDF to Image
|
pdfToImage.header=PDF to Image
|
||||||
pdfToImage.selectText=Image Format
|
pdfToImage.selectText=Image Format
|
||||||
pdfToImage.singleOrMultiple=Image result type
|
pdfToImage.singleOrMultiple=Page to Image result type
|
||||||
pdfToImage.single=Single Big Image
|
pdfToImage.single=Single Big Image Combing all pages
|
||||||
pdfToImage.multi=Multiple Images
|
pdfToImage.multi=Multiple Images, one image per page
|
||||||
pdfToImage.colorType=Colour type
|
pdfToImage.colorType=Colour type
|
||||||
pdfToImage.color=Colour
|
pdfToImage.color=Colour
|
||||||
pdfToImage.grey=Greyscale
|
pdfToImage.grey=Greyscale
|
||||||
pdfToImage.blackwhite=Black and White (May lose data!)
|
pdfToImage.blackwhite=Black and White (May lose data!)
|
||||||
pdfToImage.submit=Convert
|
pdfToImage.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=Add Password
|
addPassword.title=Add Password
|
||||||
addPassword.header=Add password (Encrypt)
|
addPassword.header=Add password (Encrypt)
|
||||||
@@ -372,6 +678,7 @@ addPassword.selectText.15=Restricts what can be done with the document once it i
|
|||||||
addPassword.selectText.16=Restricts the opening of the document itself
|
addPassword.selectText.16=Restricts the opening of the document itself
|
||||||
addPassword.submit=Encrypt
|
addPassword.submit=Encrypt
|
||||||
|
|
||||||
|
|
||||||
#watermark
|
#watermark
|
||||||
watermark.title=Add Watermark
|
watermark.title=Add Watermark
|
||||||
watermark.header=Add Watermark
|
watermark.header=Add Watermark
|
||||||
@@ -382,14 +689,10 @@ watermark.selectText.4=Rotation (0-360):
|
|||||||
watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
|
watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
|
||||||
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
|
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
|
||||||
watermark.selectText.7=Opacity (0% - 100%):
|
watermark.selectText.7=Opacity (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=Add Watermark
|
watermark.submit=Add Watermark
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=Remove Watermark
|
|
||||||
remove-watermark.header=Remove Watermark
|
|
||||||
remove-watermark.selectText.1=Select PDF to remove watermark from:
|
|
||||||
remove-watermark.selectText.2=Watermark Text:
|
|
||||||
remove-watermark.submit=Remove Watermark
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=Change Permissions
|
permissions.title=Change Permissions
|
||||||
@@ -407,6 +710,7 @@ permissions.selectText.9=Prevent printing
|
|||||||
permissions.selectText.10=Prevent printing different formats
|
permissions.selectText.10=Prevent printing different formats
|
||||||
permissions.submit=Change
|
permissions.submit=Change
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=Remove password
|
removePassword.title=Remove password
|
||||||
removePassword.header=Remove password (Decrypt)
|
removePassword.header=Remove password (Decrypt)
|
||||||
@@ -414,6 +718,8 @@ removePassword.selectText.1=Select PDF to Decrypt
|
|||||||
removePassword.selectText.2=Password
|
removePassword.selectText.2=Password
|
||||||
removePassword.submit=Remove
|
removePassword.submit=Remove
|
||||||
|
|
||||||
|
|
||||||
|
#changeMetadata
|
||||||
changeMetadata.title=Change Metadata
|
changeMetadata.title=Change Metadata
|
||||||
changeMetadata.header=Change Metadata
|
changeMetadata.header=Change Metadata
|
||||||
changeMetadata.selectText.1=Please edit the variables you wish to change
|
changeMetadata.selectText.1=Please edit the variables you wish to change
|
||||||
@@ -432,27 +738,30 @@ changeMetadata.selectText.4=Other Metadata:
|
|||||||
changeMetadata.selectText.5=Add Custom Metadata Entry
|
changeMetadata.selectText.5=Add Custom Metadata Entry
|
||||||
changeMetadata.submit=Change
|
changeMetadata.submit=Change
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=Excel to PDF
|
xlsToPdf.title=Excel to PDF
|
||||||
xlsToPdf.header=Excel to PDF
|
xlsToPdf.header=Excel to PDF
|
||||||
xlsToPdf.selectText.1=Select XLS or XLSX Excel sheet to convert
|
xlsToPdf.selectText.1=Select XLS or XLSX Excel sheet to convert
|
||||||
xlsToPdf.convert=convert
|
xlsToPdf.convert=convert
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
|
||||||
pdfToPDFA.title=PDF To PDF/A
|
pdfToPDFA.title=PDF To PDF/A
|
||||||
pdfToPDFA.header=PDF To PDF/A
|
pdfToPDFA.header=PDF To PDF/A
|
||||||
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
||||||
pdfToPDFA.submit=Convert
|
pdfToPDFA.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=PDF to Word
|
PDFToWord.title=PDF to Word
|
||||||
PDFToWord.header=PDF to Word
|
PDFToWord.header=PDF to Word
|
||||||
PDFToWord.selectText.1=Output file format
|
PDFToWord.selectText.1=Output file format
|
||||||
PDFToWord.credit=This service uses LibreOffice for file conversion.
|
PDFToWord.credit=This service uses LibreOffice for file conversion.
|
||||||
PDFToWord.submit=Convert
|
PDFToWord.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDF to Presentation
|
PDFToPresentation.title=PDF to Presentation
|
||||||
PDFToPresentation.header=PDF to Presentation
|
PDFToPresentation.header=PDF to Presentation
|
||||||
PDFToPresentation.selectText.1=Output file format
|
PDFToPresentation.selectText.1=Output file format
|
||||||
@@ -460,31 +769,23 @@ PDFToPresentation.credit=This service uses LibreOffice for file conversion.
|
|||||||
PDFToPresentation.submit=Convert
|
PDFToPresentation.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
PDFToText.title=PDF to Text/RTF
|
#PDFToText
|
||||||
PDFToText.header=PDF to Text/RTF
|
PDFToText.title=PDF to RTF (Text)
|
||||||
|
PDFToText.header=PDF to RTF (Text)
|
||||||
PDFToText.selectText.1=Output file format
|
PDFToText.selectText.1=Output file format
|
||||||
PDFToText.credit=This service uses LibreOffice for file conversion.
|
PDFToText.credit=This service uses LibreOffice for file conversion.
|
||||||
PDFToText.submit=Convert
|
PDFToText.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDF to HTML
|
PDFToHTML.title=PDF to HTML
|
||||||
PDFToHTML.header=PDF to HTML
|
PDFToHTML.header=PDF to HTML
|
||||||
PDFToHTML.credit=This service uses LibreOffice for file conversion.
|
PDFToHTML.credit=This service uses LibreOffice for file conversion.
|
||||||
PDFToHTML.submit=Convert
|
PDFToHTML.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=PDF to XML
|
PDFToXML.title=PDF to XML
|
||||||
PDFToXML.header=PDF to XML
|
PDFToXML.header=PDF to XML
|
||||||
PDFToXML.credit=This service uses LibreOffice for file conversion.
|
PDFToXML.credit=This service uses LibreOffice for file conversion.
|
||||||
PDFToXML.submit=Convert
|
PDFToXML.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
794
src/main/resources/messages_en_US.properties
Normal file
794
src/main/resources/messages_en_US.properties
Normal file
@@ -0,0 +1,794 @@
|
|||||||
|
###########
|
||||||
|
# Generic #
|
||||||
|
###########
|
||||||
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
|
language.direction=ltr
|
||||||
|
|
||||||
|
pdfPrompt=Select PDF(s)
|
||||||
|
multiPdfPrompt=Select PDFs (2+)
|
||||||
|
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
||||||
|
imgPrompt=Select Image(s)
|
||||||
|
genericSubmit=Submit
|
||||||
|
processTimeWarning=Warning: This process can take up to a minute depending on file-size
|
||||||
|
pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) :
|
||||||
|
goToPage=Go
|
||||||
|
true=True
|
||||||
|
false=False
|
||||||
|
unknown=Unknown
|
||||||
|
save=Save
|
||||||
|
close=Close
|
||||||
|
filesSelected=files selected
|
||||||
|
noFavourites=No favorites added
|
||||||
|
bored=Bored Waiting?
|
||||||
|
alphabet=Alphabet
|
||||||
|
downloadPdf=Download PDF
|
||||||
|
text=Text
|
||||||
|
font=Font
|
||||||
|
selectFillter=-- Select --
|
||||||
|
pageNum=Page Number
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
|
navbar.convert=Convert
|
||||||
|
navbar.security=Security
|
||||||
|
navbar.other=Other
|
||||||
|
navbar.darkmode=Dark Mode
|
||||||
|
navbar.pageOps=Page Operations
|
||||||
|
navbar.settings=Settings
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=Settings
|
||||||
|
settings.update=Update available
|
||||||
|
settings.appVersion=App Version:
|
||||||
|
settings.downloadOption.title=Choose download option (For single file non zip downloads):
|
||||||
|
settings.downloadOption.1=Open in same window
|
||||||
|
settings.downloadOption.2=Open in new window
|
||||||
|
settings.downloadOption.3=Download file
|
||||||
|
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
|
#############
|
||||||
|
# HOME-PAGE #
|
||||||
|
#############
|
||||||
|
home.desc=Your locally hosted one-stop-shop for all your PDF needs.
|
||||||
|
|
||||||
|
|
||||||
|
home.multiTool.title=PDF Multi Tool
|
||||||
|
home.multiTool.desc=Merge, Rotate, Rearrange, and Remove pages
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side,interactive,intractable,move
|
||||||
|
|
||||||
|
home.merge.title=Merge
|
||||||
|
home.merge.desc=Easily merge multiple PDFs into one.
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
|
home.split.title=Split
|
||||||
|
home.split.desc=Split PDFs into multiple documents
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
|
home.rotate.title=Rotate
|
||||||
|
home.rotate.desc=Easily rotate your PDFs.
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
|
home.imageToPdf.title=Image to PDF
|
||||||
|
home.imageToPdf.desc=Convert a image (PNG, JPEG, GIF) to PDF.
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.pdfToImage.title=PDF to Image
|
||||||
|
home.pdfToImage.desc=Convert a PDF to a image. (PNG, JPEG, GIF)
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.pdfOrganiser.title=Organize
|
||||||
|
home.pdfOrganiser.desc=Remove/Rearrange pages in any order
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
|
home.addImage.title=Add image
|
||||||
|
home.addImage.desc=Adds a image onto a set location on the PDF
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.watermark.title=Add Watermark
|
||||||
|
home.watermark.desc=Add a custom watermark to your PDF document.
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
|
|
||||||
|
home.permissions.title=Change Permissions
|
||||||
|
home.permissions.desc=Change the permissions of your PDF document
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
|
home.removePages.title=Remove
|
||||||
|
home.removePages.desc=Delete unwanted pages from your PDF document.
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
|
home.addPassword.title=Add Password
|
||||||
|
home.addPassword.desc=Encrypt your PDF document with a password.
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
|
home.removePassword.title=Remove Password
|
||||||
|
home.removePassword.desc=Remove password protection from your PDF document.
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
|
home.compressPdfs.title=Compress
|
||||||
|
home.compressPdfs.desc=Compress PDFs to reduce their file size.
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
|
home.changeMetadata.title=Change Metadata
|
||||||
|
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
|
home.fileToPDF.title=Convert file to PDF
|
||||||
|
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
|
home.ocr.title=OCR / Cleanup scans
|
||||||
|
home.ocr.desc=Cleanup scans and detects text from images within a PDF and re-adds it as text.
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
|
home.extractImages.title=Extract Images
|
||||||
|
home.extractImages.desc=Extracts all images from a PDF and saves them to zip
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
|
home.pdfToPDFA.title=PDF to PDF/A
|
||||||
|
home.pdfToPDFA.desc=Convert PDF to PDF/A for long-term storage
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
|
home.PDFToWord.title=PDF to Word
|
||||||
|
home.PDFToWord.desc=Convert PDF to Word formats (DOC, DOCX and ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
|
home.PDFToPresentation.title=PDF to Presentation
|
||||||
|
home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
|
home.PDFToText.title=PDF to RTF (Text)
|
||||||
|
home.PDFToText.desc=Convert PDF to Text or RTF format
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
|
home.PDFToHTML.title=PDF to HTML
|
||||||
|
home.PDFToHTML.desc=Convert PDF to HTML format
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
|
home.PDFToXML.title=PDF to XML
|
||||||
|
home.PDFToXML.desc=Convert PDF to XML format
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
|
home.ScannerImageSplit.title=Detect/Split Scanned photos
|
||||||
|
home.ScannerImageSplit.desc=Splits multiple photos from within a photo/PDF
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
|
home.sign.title=Sign
|
||||||
|
home.sign.desc=Adds signature to PDF by drawing, text or image
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
|
home.flatten.title=Flatten
|
||||||
|
home.flatten.desc=Remove all interactive elements and forms from a PDF
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
|
home.repair.title=Repair
|
||||||
|
home.repair.desc=Tries to repair a corrupt/broken PDF
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
|
home.removeBlanks.title=Remove Blank pages
|
||||||
|
home.removeBlanks.desc=Detects and removes blank pages from a document
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
|
|
||||||
|
home.compare.title=Compare
|
||||||
|
home.compare.desc=Compares and shows the differences between 2 PDF Documents
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
|
home.certSign.title=Sign with Certificate
|
||||||
|
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
|
home.pageLayout.title=Multi-Page Layout
|
||||||
|
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
|
home.scalePages.title=Adjust page size/scale
|
||||||
|
home.scalePages.desc=Change the size/scale of a page and/or its contents.
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
|
pageLayout.title=Multi Page Layout
|
||||||
|
pageLayout.header=Multi Page Layout
|
||||||
|
pageLayout.pagesPerSheet=Pages per sheet:
|
||||||
|
pageLayout.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
|
scalePages.title=Adjust page-scale
|
||||||
|
scalePages.header=Adjust page-scale
|
||||||
|
scalePages.pageSize=Size of a page of the document.
|
||||||
|
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||||
|
scalePages.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
|
certSign.title=Certificate Signing
|
||||||
|
certSign.header=Sign a PDF with your certificate (Work in progress)
|
||||||
|
certSign.selectPDF=Select a PDF File for Signing:
|
||||||
|
certSign.selectKey=Select Your Private Key File (PKCS#8 format, could be .pem or .der):
|
||||||
|
certSign.selectCert=Select Your Certificate File (X.509 format, could be .pem or .der):
|
||||||
|
certSign.selectP12=Select Your PKCS#12 Keystore File (.p12 or .pfx) (Optional, If provided, it should contain your private key and certificate):
|
||||||
|
certSign.certType=Certificate Type
|
||||||
|
certSign.password=Enter Your Keystore or Private Key Password (If Any):
|
||||||
|
certSign.showSig=Show Signature
|
||||||
|
certSign.reason=Reason
|
||||||
|
certSign.location=Location
|
||||||
|
certSign.name=Name
|
||||||
|
certSign.submit=Sign PDF
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
|
removeBlanks.title=Remove Blanks
|
||||||
|
removeBlanks.header=Remove Blank Pages
|
||||||
|
removeBlanks.threshold=Pixel Whiteness Threshold:
|
||||||
|
removeBlanks.thresholdDesc=Threshold for determining how white a white pixel must be to be classed as 'White'. 0 = Black, 255 pure white.
|
||||||
|
removeBlanks.whitePercent=White Percent (%):
|
||||||
|
removeBlanks.whitePercentDesc=Percent of page that must be 'white' pixels to be removed
|
||||||
|
removeBlanks.submit=Remove Blanks
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
|
compare.title=Compare
|
||||||
|
compare.header=Compare PDFs
|
||||||
|
compare.document.1=Document 1
|
||||||
|
compare.document.2=Document 2
|
||||||
|
compare.submit=Compare
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
|
sign.title=Sign
|
||||||
|
sign.header=Sign PDFs
|
||||||
|
sign.upload=Upload Image
|
||||||
|
sign.draw=Draw Signature
|
||||||
|
sign.text=Text Input
|
||||||
|
sign.clear=Clear
|
||||||
|
sign.add=Add
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
|
repair.title=Repair
|
||||||
|
repair.header=Repair PDFs
|
||||||
|
repair.submit=Repair
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
|
flatten.title=Flatten
|
||||||
|
flatten.header=Flatten PDFs
|
||||||
|
flatten.submit=Flatten
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
|
ScannerImageSplit.selectText.1=Angle Threshold:
|
||||||
|
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
|
||||||
|
ScannerImageSplit.selectText.3=Tolerance:
|
||||||
|
ScannerImageSplit.selectText.4=Determines the range of color variation around the estimated background color (default: 30).
|
||||||
|
ScannerImageSplit.selectText.5=Minimum Area:
|
||||||
|
ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000).
|
||||||
|
ScannerImageSplit.selectText.7=Minimum Contour Area:
|
||||||
|
ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo
|
||||||
|
ScannerImageSplit.selectText.9=Border Size:
|
||||||
|
ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1).
|
||||||
|
|
||||||
|
|
||||||
|
#OCR
|
||||||
|
ocr.title=OCR / Scan Cleanup
|
||||||
|
ocr.header=Cleanup Scans / OCR (Optical Character Recognition)
|
||||||
|
ocr.selectText.1=Select languages that are to be detected within the PDF (Ones listed are the ones currently detected):
|
||||||
|
ocr.selectText.2=Produce text file containing OCR text alongside the OCR'ed PDF
|
||||||
|
ocr.selectText.3=Correct pages were scanned at a skewed angle by rotating them back into place
|
||||||
|
ocr.selectText.4=Clean page so its less likely that OCR will find text in background noise. (No output change)
|
||||||
|
ocr.selectText.5=Clean page so its less likely that OCR will find text in background noise, maintains cleanup in output.
|
||||||
|
ocr.selectText.6=Ignores pages that have interactive text on them, only OCRs pages that are images
|
||||||
|
ocr.selectText.7=Force OCR, will OCR Every page removing all original text elements
|
||||||
|
ocr.selectText.8=Normal (Will error if PDF contains text)
|
||||||
|
ocr.selectText.9=Additional Settings
|
||||||
|
ocr.selectText.10=OCR Mode
|
||||||
|
ocr.selectText.11=Remove images after OCR (Removes ALL images, only useful if part of conversion step)
|
||||||
|
ocr.selectText.12=Render Type (Advanced)
|
||||||
|
ocr.help=Please read this documentation on how to use this for other languages and/or use not in docker
|
||||||
|
ocr.credit=This service uses OCRmyPDF and Tesseract for OCR.
|
||||||
|
ocr.submit=Process PDF with OCR
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
|
extractImages.title=Extract Images
|
||||||
|
extractImages.header=Extract Images
|
||||||
|
extractImages.selectText=Select image format to convert extracted images to
|
||||||
|
extractImages.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#File to PDF
|
||||||
|
fileToPDF.title=File to PDF
|
||||||
|
fileToPDF.header=Convert any file to PDF
|
||||||
|
fileToPDF.credit=This service uses LibreOffice and Unoconv for file conversion.
|
||||||
|
fileToPDF.supportedFileTypes=Supported file types should include the below however for a full updated list of supported formats, please refer to the LibreOffice documentation
|
||||||
|
fileToPDF.submit=Convert to PDF
|
||||||
|
|
||||||
|
|
||||||
|
#compress
|
||||||
|
compress.title=Compress
|
||||||
|
compress.header=Compress PDF
|
||||||
|
compress.credit=This service uses Ghostscript for PDF Compress/Optimisation.
|
||||||
|
compress.selectText.1=Manual Mode - From 1 to 4
|
||||||
|
compress.selectText.2=Optimization level:
|
||||||
|
compress.selectText.3=4 (Terrible for text images)
|
||||||
|
compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size
|
||||||
|
compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)
|
||||||
|
compress.submit=Compress
|
||||||
|
|
||||||
|
|
||||||
|
#Add image
|
||||||
|
addImage.title=Add Image
|
||||||
|
addImage.header=Add image to PDF
|
||||||
|
addImage.everyPage=Every Page?
|
||||||
|
addImage.upload=Add image
|
||||||
|
addImage.submit=Add image
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
merge.title=Merge
|
||||||
|
merge.header=Merge multiple PDFs (2+)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
|
merge.submit=Merge
|
||||||
|
|
||||||
|
|
||||||
|
#pdfOrganiser
|
||||||
|
pdfOrganiser.title=Page Organizer
|
||||||
|
pdfOrganiser.header=PDF Page Organizer
|
||||||
|
pdfOrganiser.submit=Rearrange Pages
|
||||||
|
|
||||||
|
|
||||||
|
#multiTool
|
||||||
|
multiTool.title=PDF Multi Tool
|
||||||
|
multiTool.header=PDF Multi Tool
|
||||||
|
|
||||||
|
|
||||||
|
#pageRemover
|
||||||
|
pageRemover.title=Page Remover
|
||||||
|
pageRemover.header=PDF Page remover
|
||||||
|
pageRemover.pagesToDelete=Pages to delete (Enter a comma-separated list of page numbers) :
|
||||||
|
pageRemover.submit=Delete Pages
|
||||||
|
|
||||||
|
|
||||||
|
#rotate
|
||||||
|
rotate.title=Rotate PDF
|
||||||
|
rotate.header=Rotate PDF
|
||||||
|
rotate.selectAngle=Select rotation angle (in multiples of 90 degrees):
|
||||||
|
rotate.submit=Rotate
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
split.title=Split PDF
|
||||||
|
split.header=Split PDF
|
||||||
|
split.desc.1=The numbers you select are the page number you wish to do a split on
|
||||||
|
split.desc.2=As such selecting 1,3,7-8 would split a 10 page document into 6 separate PDFS with:
|
||||||
|
split.desc.3=Document #1: Page 1
|
||||||
|
split.desc.4=Document #2: Page 2 and 3
|
||||||
|
split.desc.5=Document #3: Page 4, 5 and 6
|
||||||
|
split.desc.6=Document #4: Page 7
|
||||||
|
split.desc.7=Document #5: Page 8
|
||||||
|
split.desc.8=Document #6: Page 9 and 10
|
||||||
|
split.splitPages=Enter pages to split on:
|
||||||
|
split.submit=Split
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
imageToPDF.title=Image to PDF
|
||||||
|
imageToPDF.header=Image to PDF
|
||||||
|
imageToPDF.submit=Convert
|
||||||
|
imageToPDF.selectText.1=Stretch to fit
|
||||||
|
imageToPDF.selectText.2=Auto rotate PDF
|
||||||
|
imageToPDF.selectText.3=Multi file logic (Only enabled if working with multiple images)
|
||||||
|
imageToPDF.selectText.4=Merge into single PDF
|
||||||
|
imageToPDF.selectText.5=Convert to separate PDFs
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToImage
|
||||||
|
pdfToImage.title=PDF to Image
|
||||||
|
pdfToImage.header=PDF to Image
|
||||||
|
pdfToImage.selectText=Image Format
|
||||||
|
pdfToImage.singleOrMultiple=Image result type
|
||||||
|
pdfToImage.single=Single Big Image
|
||||||
|
pdfToImage.multi=Multiple Images
|
||||||
|
pdfToImage.colorType=Color type
|
||||||
|
pdfToImage.color=Color
|
||||||
|
pdfToImage.grey=Grayscale
|
||||||
|
pdfToImage.blackwhite=Black and White (May lose data!)
|
||||||
|
pdfToImage.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#addPassword
|
||||||
|
addPassword.title=Add Password
|
||||||
|
addPassword.header=Add password (Encrypt)
|
||||||
|
addPassword.selectText.1=Select PDF to encrypt
|
||||||
|
addPassword.selectText.2=User Password
|
||||||
|
addPassword.selectText.3=Encryption Key Length
|
||||||
|
addPassword.selectText.4=Higher values are stronger, but lower values have better compatibility.
|
||||||
|
addPassword.selectText.5=Permissions to set (Recommended to be used along with Owner password)
|
||||||
|
addPassword.selectText.6=Prevent assembly of document
|
||||||
|
addPassword.selectText.7=Prevent content extraction
|
||||||
|
addPassword.selectText.8=Prevent extraction for accessibility
|
||||||
|
addPassword.selectText.9=Prevent filling in form
|
||||||
|
addPassword.selectText.10=Prevent modification
|
||||||
|
addPassword.selectText.11=Prevent annotation modification
|
||||||
|
addPassword.selectText.12=Prevent printing
|
||||||
|
addPassword.selectText.13=Prevent printing different formats
|
||||||
|
addPassword.selectText.14=Owner Password
|
||||||
|
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
|
||||||
|
addPassword.selectText.16=Restricts the opening of the document itself
|
||||||
|
addPassword.submit=Encrypt
|
||||||
|
|
||||||
|
|
||||||
|
#watermark
|
||||||
|
watermark.title=Add Watermark
|
||||||
|
watermark.header=Add Watermark
|
||||||
|
watermark.selectText.1=Select PDF to add watermark to:
|
||||||
|
watermark.selectText.2=Watermark Text:
|
||||||
|
watermark.selectText.3=Font Size:
|
||||||
|
watermark.selectText.4=Rotation (0-360):
|
||||||
|
watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
|
||||||
|
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
|
||||||
|
watermark.selectText.7=Opacity (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
|
watermark.submit=Add Watermark
|
||||||
|
|
||||||
|
|
||||||
|
#Change permissions
|
||||||
|
permissions.title=Change Permissions
|
||||||
|
permissions.header=Change Permissions
|
||||||
|
permissions.warning=Warning to have these permissions be unchangeable it is recommended to set them with a password via the add-password page
|
||||||
|
permissions.selectText.1=Select PDF to change permissions
|
||||||
|
permissions.selectText.2=Permissions to set
|
||||||
|
permissions.selectText.3=Prevent assembly of document
|
||||||
|
permissions.selectText.4=Prevent content extraction
|
||||||
|
permissions.selectText.5=Prevent extraction for accessibility
|
||||||
|
permissions.selectText.6=Prevent filling in form
|
||||||
|
permissions.selectText.7=Prevent modification
|
||||||
|
permissions.selectText.8=Prevent annotation modification
|
||||||
|
permissions.selectText.9=Prevent printing
|
||||||
|
permissions.selectText.10=Prevent printing different formats
|
||||||
|
permissions.submit=Change
|
||||||
|
|
||||||
|
|
||||||
|
#remove password
|
||||||
|
removePassword.title=Remove password
|
||||||
|
removePassword.header=Remove password (Decrypt)
|
||||||
|
removePassword.selectText.1=Select PDF to Decrypt
|
||||||
|
removePassword.selectText.2=Password
|
||||||
|
removePassword.submit=Remove
|
||||||
|
|
||||||
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=Title:
|
||||||
|
changeMetadata.header=Change Metadata
|
||||||
|
changeMetadata.selectText.1=Please edit the variables you wish to change
|
||||||
|
changeMetadata.selectText.2=Delete all metadata
|
||||||
|
changeMetadata.selectText.3=Show Custom Metadata:
|
||||||
|
changeMetadata.author=Author:
|
||||||
|
changeMetadata.creationDate=Creation Date (yyyy/MM/dd HH:mm:ss):
|
||||||
|
changeMetadata.creator=Creator:
|
||||||
|
changeMetadata.keywords=Keywords:
|
||||||
|
changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss):
|
||||||
|
changeMetadata.producer=Producer:
|
||||||
|
changeMetadata.subject=Subject:
|
||||||
|
changeMetadata.title=Title:
|
||||||
|
changeMetadata.trapped=Trapped:
|
||||||
|
changeMetadata.selectText.4=Other Metadata:
|
||||||
|
changeMetadata.selectText.5=Add Custom Metadata Entry
|
||||||
|
changeMetadata.submit=Change
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
|
xlsToPdf.title=Excel to PDF
|
||||||
|
xlsToPdf.header=Excel to PDF
|
||||||
|
xlsToPdf.selectText.1=Select XLS or XLSX Excel sheet to convert
|
||||||
|
xlsToPdf.convert=convert
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
pdfToPDFA.title=PDF To PDF/A
|
||||||
|
pdfToPDFA.header=PDF To PDF/A
|
||||||
|
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
||||||
|
pdfToPDFA.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
|
PDFToWord.title=PDF to Word
|
||||||
|
PDFToWord.header=PDF to Word
|
||||||
|
PDFToWord.selectText.1=Output file format
|
||||||
|
PDFToWord.credit=This service uses LibreOffice for file conversion.
|
||||||
|
PDFToWord.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
|
PDFToPresentation.title=PDF to Presentation
|
||||||
|
PDFToPresentation.header=PDF to Presentation
|
||||||
|
PDFToPresentation.selectText.1=Output file format
|
||||||
|
PDFToPresentation.credit=This service uses LibreOffice for file conversion.
|
||||||
|
PDFToPresentation.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
|
PDFToText.title=PDF to RTF (Text)
|
||||||
|
PDFToText.header=PDF to RTF (Text)
|
||||||
|
PDFToText.selectText.1=Output file format
|
||||||
|
PDFToText.credit=This service uses LibreOffice for file conversion.
|
||||||
|
PDFToText.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
|
PDFToHTML.title=PDF to HTML
|
||||||
|
PDFToHTML.header=PDF to HTML
|
||||||
|
PDFToHTML.credit=This service uses LibreOffice for file conversion.
|
||||||
|
PDFToHTML.submit=Convert
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
|
PDFToXML.title=PDF to XML
|
||||||
|
PDFToXML.header=PDF to XML
|
||||||
|
PDFToXML.credit=This service uses LibreOffice for file conversion.
|
||||||
|
PDFToXML.submit=Convert
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=Seleccionar PDF(s)
|
pdfPrompt=Seleccionar PDF(s)
|
||||||
multiPdfPrompt=Seleccionar PDFs (2+)
|
multiPdfPrompt=Seleccionar PDFs (2+)
|
||||||
multiPdfDropPrompt=Selecciona (o arrastra y suelta) todos los PDFs que quieras
|
multiPdfDropPrompt=Seleccione (o arrastre y suelte) todos los PDFs que quiera
|
||||||
imgPrompt=Seleccionar Imagen(es)
|
imgPrompt=Seleccionar Imagen(es)
|
||||||
genericSubmit=Enviar
|
genericSubmit=Enviar
|
||||||
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
|
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
|
||||||
@@ -19,154 +19,467 @@ save=Guardar
|
|||||||
close=Cerrar
|
close=Cerrar
|
||||||
filesSelected=archivos seleccionados
|
filesSelected=archivos seleccionados
|
||||||
noFavourites=No se agregaron favoritos
|
noFavourites=No se agregaron favoritos
|
||||||
bored=¿Aburrido de esperar?
|
bored=¿Cansado de esperar?
|
||||||
alphabet=Alfabeto
|
alphabet=Alfabeto
|
||||||
#############
|
downloadPdf=Descargar PDF
|
||||||
# HOME-PAGE #
|
text=Texto
|
||||||
#############
|
font=Fuente
|
||||||
home.desc=Tu ventanilla única autohospedada para todas tus necesidades PDF
|
selectFillter=-- Seleccionar --
|
||||||
|
pageNum=Número de página
|
||||||
|
sizes.small=Paqueño
|
||||||
|
sizes.medium=Mediano
|
||||||
|
sizes.large=Grande
|
||||||
|
sizes.x-large=Extra grande
|
||||||
|
error.pdfPassword=El documento PDF está protegido con contraseña y no se ha proporcionado o es incorrecta
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
navbar.convert=Convertir
|
navbar.convert=Convertir
|
||||||
navbar.security=Seguridad
|
navbar.security=Seguridad
|
||||||
navbar.other=Otro
|
navbar.other=Otro
|
||||||
navbar.darkmode=Modo oscuro
|
navbar.darkmode=Modo oscuro
|
||||||
navbar.pageOps=Operaciones de página
|
navbar.pageOps=Operaciones de página
|
||||||
|
navbar.settings=Ajustes
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=Ajustes
|
||||||
|
settings.update=Actualización disponible
|
||||||
|
settings.appVersion=Versión de la aplicación:
|
||||||
|
settings.downloadOption.title=Elegir la opción de descarga (para descargas de un solo archivo sin ZIP):
|
||||||
|
settings.downloadOption.1=Abrir en la misma ventana
|
||||||
|
settings.downloadOption.2=Abrir en una nueva ventana
|
||||||
|
settings.downloadOption.3=Descargar el fichero
|
||||||
|
settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descargados
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
|
#############
|
||||||
|
# HOME-PAGE #
|
||||||
|
#############
|
||||||
|
home.desc=Su ventanilla única autohospedada para todas tus necesidades PDF
|
||||||
|
|
||||||
|
|
||||||
home.multiTool.title=Multi-herramienta PDF
|
home.multiTool.title=Multi-herramienta PDF
|
||||||
home.multiTool.desc=Combinar, rotar, reorganizar y eliminar páginas
|
home.multiTool.desc=Combinar, rotar, reorganizar y eliminar páginas
|
||||||
|
multiTool.tags=Multi-herramienta,Multi-operación,Interfaz de usuario,Arrastrar con un click,front end,lado del client
|
||||||
|
|
||||||
home.merge.title=Unir
|
home.merge.title=Unir
|
||||||
home.merge.desc=Unir fácilmente múltiples PDFs en uno
|
home.merge.desc=Unir fácilmente múltiples PDFs en uno
|
||||||
|
merge.tags=Unir,Operaciones de página,Back end,lado del servidor
|
||||||
|
|
||||||
home.split.title=Dividir
|
home.split.title=Dividir
|
||||||
home.split.desc=Dividir PDFs en múltiples documentos
|
home.split.desc=Dividir PDFs en múltiples documentos
|
||||||
|
split.tags=Operaciones de página,dividir,Multi-página,cortar,lado del servidor
|
||||||
|
|
||||||
home.rotate.title=Rotar
|
home.rotate.title=Rotar
|
||||||
home.rotate.desc=Rotar fácilmente tus PDFs
|
home.rotate.desc=Rotar fácilmente sus PDFs
|
||||||
|
rotate.tags=lado del servidor
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=Imagen a PDF
|
home.imageToPdf.title=Imagen a PDF
|
||||||
home.imageToPdf.desc=Convertir una imagen (PNG, JPEG, GIF) a PDF
|
home.imageToPdf.desc=Convertir una imagen (PNG, JPEG, GIF) a PDF
|
||||||
|
imageToPdf.tags=conversión,img,jpg,imagen,fotografía
|
||||||
|
|
||||||
home.pdfToImage.title=PDF a Imagen
|
home.pdfToImage.title=PDF a Imagen
|
||||||
home.pdfToImage.desc=Convertir un PDF a una imagen (PNG, JPEG, GIF)
|
home.pdfToImage.desc=Convertir un PDF a una imagen (PNG, JPEG, GIF)
|
||||||
|
pdfToImage.tags=conversión,img,jpg,imagen,fotografía
|
||||||
|
|
||||||
home.pdfOrganiser.title=Organizador
|
home.pdfOrganiser.title=Organizador
|
||||||
home.pdfOrganiser.desc=Eliminar/Reorganizar páginas en cualquier orden
|
home.pdfOrganiser.desc=Eliminar/Reorganizar páginas en cualquier orden
|
||||||
|
pdfOrganiser.tags=doble cara,pares,impares,ordenar,mover
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=Agregar imagen al PDF
|
home.addImage.title=Agregar imagen al PDF
|
||||||
home.addImage.desc=Agregar una imagen en una ubicación establecida en el PDF (trabajo en progreso)
|
home.addImage.desc=Agregar una imagen en una ubicación establecida en el PDF (en desarrollo)
|
||||||
|
addImage.tags=img,jpg,imagen,fotografía
|
||||||
|
|
||||||
home.watermark.title=Añadir marca de agua
|
home.watermark.title=Añadir marca de agua
|
||||||
home.watermark.desc=Añadir una marca de agua predefinida al documento PDF
|
home.watermark.desc=Añadir una marca de agua predefinida al documento PDF
|
||||||
|
watermark.tags=Texto,repetir,etiquetar,propietario,copyight,marca comercial,img,jpg,imagen,fotografía
|
||||||
home.remove-watermark.title=Eliminar marca de agua
|
|
||||||
home.remove-watermark.desc=Eliminar marca de agua de tu documento PDF
|
|
||||||
|
|
||||||
home.permissions.title=Cambiar permisos
|
home.permissions.title=Cambiar permisos
|
||||||
home.permissions.desc=Cambiar los permisos del documento PDF
|
home.permissions.desc=Cambiar los permisos del documento PDF
|
||||||
|
permissions.tags=leer,escribir,editar,imprimir
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=Eliminar
|
home.removePages.title=Eliminar
|
||||||
home.removePages.desc=Eliminar páginas no deseadas del documento PDF
|
home.removePages.desc=Eliminar páginas no deseadas del documento PDF
|
||||||
|
removePages.tags=Borrar páginas,eliminar páginas
|
||||||
|
|
||||||
home.addPassword.title=Añadir contraseña
|
home.addPassword.title=Añadir contraseña
|
||||||
home.addPassword.desc=Encriptar el documento PDF con una contraseña
|
home.addPassword.desc=Encriptar el documento PDF con una contraseña
|
||||||
|
addPassword.tags=seguro,seguridad
|
||||||
|
|
||||||
home.removePassword.title=Eliminar contraseña
|
home.removePassword.title=Eliminar contraseña
|
||||||
home.removePassword.desc=Eliminar la contraseña del documento PDF
|
home.removePassword.desc=Eliminar la contraseña del documento PDF
|
||||||
|
removePassword.tags=seguro,Desencriptar,seguridad,quitar contraseña,eliminar contraseña
|
||||||
|
|
||||||
home.compressPdfs.title=Comprimir
|
home.compressPdfs.title=Comprimir
|
||||||
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del fichero
|
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del fichero
|
||||||
|
compressPdfs.tags=aplastar,pequeño,diminuto
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=Cambiar metadatos
|
home.changeMetadata.title=Cambiar metadatos
|
||||||
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
|
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
|
||||||
|
changeMetadata.tags==Título,autor,fecha,creación,hora,editorial,productor,estadísticas
|
||||||
|
|
||||||
home.fileToPDF.title=Convertir fichero a PDF
|
home.fileToPDF.title=Convertir fichero a PDF
|
||||||
home.fileToPDF.desc=Convertir casi cualquier archivo a PDF (DOCX, PNG, XLS, PPT, TXT y más)
|
home.fileToPDF.desc=Convertir casi cualquier archivo a PDF (DOCX, PNG, XLS, PPT, TXT y más)
|
||||||
|
fileToPDF.tags=transformación,formato,documento,imagen,diapositiva,texto,conversión,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
|
home.ocr.title=Ejecutar OCR en PDF y/o tareas de limpieza
|
||||||
|
home.ocr.desc=Tareas de limpieza y detectar texto en imágenes dentro de un PDF y volver a incrustarlo como texto
|
||||||
|
ocr.tags=reconocimiento,texto,imagen,escanear,leer,identificar,detección,editable
|
||||||
|
|
||||||
home.ocr.title=Ejecutar OCR en PDF y/o escaneos de limpieza
|
|
||||||
home.ocr.desc=Escaneos de limpieza y detectar texto de imágenes dentro de un PDF y volver a agregarlo como texto
|
|
||||||
|
|
||||||
home.extractImages.title=Extraer imágenes
|
home.extractImages.title=Extraer imágenes
|
||||||
home.extractImages.desc=Extraer todas las imágenes de un PDF y guardarlas en ZIP
|
home.extractImages.desc=Extraer todas las imágenes de un PDF y guardarlas en ZIP
|
||||||
|
extractImages.tags=imagen,fotografía,guardar,archivo,zip,capturar,coger
|
||||||
|
|
||||||
home.pdfToPDFA.title=Convertir PDF a PDF/A
|
home.pdfToPDFA.title=Convertir PDF a PDF/A
|
||||||
home.pdfToPDFA.desc=Convertir PDF a PDF/A para almacenamiento a largo plazo
|
home.pdfToPDFA.desc=Convertir PDF a PDF/A para almacenamiento a largo plazo
|
||||||
|
pdfToPDFA.tags=archivo,largo plazo,estándar,conversión,almacewnamiento,conservación
|
||||||
|
|
||||||
home.PDFToWord.title=PDF a Word
|
home.PDFToWord.title=PDF a Word
|
||||||
home.PDFToWord.desc=Convertir formatos PDF a Word (DOC, DOCX y ODT)
|
home.PDFToWord.desc=Convertir formatos PDF a Word (DOC, DOCX y ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformación,formato,conversión,office,microsoft,archivo del documento
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDF a presentación
|
home.PDFToPresentation.title=PDF a presentación
|
||||||
home.PDFToPresentation.desc=Convertir PDF a formatos de presentación (PPT, PPTX y ODP)
|
home.PDFToPresentation.desc=Convertir PDF a formatos de presentación (PPT, PPTX y ODP)
|
||||||
|
PDFToPresentation.tags=diapositivas,mostrar,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=PDF a TXT o RTF
|
home.PDFToText.title=PDF a TXT o RTF
|
||||||
home.PDFToText.desc=Convertir PDF a formato TXT o RTF
|
home.PDFToText.desc=Convertir PDF a formato TXT o RTF
|
||||||
|
PDFToText.tags=formato enriquecido,formato de texto enriquecido,formato de texto enriquecido
|
||||||
|
|
||||||
home.PDFToHTML.title=PDF a HTML
|
home.PDFToHTML.title=PDF a HTML
|
||||||
home.PDFToHTML.desc=Convertir PDF a formato HTML
|
home.PDFToHTML.desc=Convertir PDF a formato HTML
|
||||||
|
PDFToHTML.tags=contenido web,amigable para navegador
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=PDF a XML
|
home.PDFToXML.title=PDF a XML
|
||||||
home.PDFToXML.desc=Convertir PDF a formato XML
|
home.PDFToXML.desc=Convertir PDF a formato XML
|
||||||
|
PDFToXML.tags=extracción de datos,contenido estructurado,interopersabilidad,transformación,convertir
|
||||||
|
|
||||||
home.ScannerImageSplit.title=Detectar/Dividir fotos escaneadas
|
home.ScannerImageSplit.title=Detectar/Dividir fotos escaneadas
|
||||||
home.ScannerImageSplit.desc=Dividir varias fotos dentro de una foto/PDF
|
home.ScannerImageSplit.desc=Dividir varias fotos dentro de una foto/PDF
|
||||||
|
ScannerImageSplit.tags=separar,auto-detectar,escaneos,multi-foto,organizar
|
||||||
|
|
||||||
home.sign.title=Firmar
|
home.sign.title=Firmar
|
||||||
home.sign.desc=Añadir firma a PDF mediante dibujo, texto o imagen
|
home.sign.desc=Añadir firma a PDF mediante dibujo, texto o imagen
|
||||||
|
sign.tags=autorizar,iniciales,firma manuscrita,texto de firma,imagen de firma
|
||||||
|
|
||||||
home.flatten.title=Aplanar
|
home.flatten.title=Aplanar
|
||||||
home.flatten.desc=Eliminar todos los elementos y formularios interactivos de un PDF
|
home.flatten.desc=Eliminar todos los elementos y formularios interactivos de un PDF
|
||||||
|
flatten.tags=estática,desactivar,no interactiva,etiqueta dinámica
|
||||||
|
|
||||||
home.repair.title=Reparar
|
home.repair.title=Reparar
|
||||||
home.repair.desc=Intentar reparar un PDF corrupto/roto
|
home.repair.desc=Intentar reparar un PDF corrupto/roto
|
||||||
|
repair.tags=reparar,restaurar,corregir,recuperar
|
||||||
|
|
||||||
home.removeBlanks.title=Eliminar páginas en blanco
|
home.removeBlanks.title=Eliminar páginas en blanco
|
||||||
home.removeBlanks.desc=Detectar y eliminar páginas en blanco de un documento
|
home.removeBlanks.desc=Detectar y eliminar páginas en blanco de un documento
|
||||||
|
removeBlanks.tags=limpieza,dinámica,sin contenido,organizar
|
||||||
home.certSign.title=Firmar con certificado
|
|
||||||
home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12)
|
|
||||||
|
|
||||||
home.compare.title=Comparar
|
home.compare.title=Comparar
|
||||||
home.compare.desc=Comparar y mostrar las diferencias entre 2 documentos PDF
|
home.compare.desc=Comparar y mostrar las diferencias entre 2 documentos PDF
|
||||||
|
compare.tags=diferenciar,contrastar,cambios,análisis
|
||||||
|
|
||||||
|
home.certSign.title=Firmar con certificado
|
||||||
|
home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12)
|
||||||
|
certSign.tags=autentificar,PEM,P12,oficial,encriptar
|
||||||
|
|
||||||
home.pageLayout.title=Diseño de varias páginas
|
home.pageLayout.title=Diseño de varias páginas
|
||||||
home.pageLayout.desc=Unir varias páginas de un documento PDF en una sola página
|
home.pageLayout.desc=Unir varias páginas de un documento PDF en una sola página
|
||||||
|
pageLayout.tags=unir,compuesto,vista única,organizar
|
||||||
|
|
||||||
home.scalePages.title=Escalar/ajustar tamaño de página
|
home.scalePages.title=Escalar/ajustar tamaño de página
|
||||||
home.scalePages.desc=Escalar/cambiar el tamaño de una pagina y/o su contenido
|
home.scalePages.desc=Escalar/cambiar el tamaño de una pagina y/o su contenido
|
||||||
|
scalePages.tags=cambiar tamaño,modificar,dimensionar,adaptar
|
||||||
|
|
||||||
error.pdfPassword=El documento PDF está protegido con contraseña y no se ha proporcionado o es incorrecta
|
home.pipeline.title=Secuencia (Avanzado)
|
||||||
|
home.pipeline.desc=Ejecutar varias tareas a PDFs definiendo una secuencia de comandos
|
||||||
|
pipeline.tags=automatizar,secuencia,con script,proceso por lotes
|
||||||
|
|
||||||
downloadPdf=Descargar PDF
|
home.add-page-numbers.title=Aádir números de página
|
||||||
text=Texto
|
home.add-page-numbers.desc=Aádir números de página en un documento en una ubicación concreta
|
||||||
font=Fuente
|
add-page-numbers.tags=paginar,etiquetar,organizar,indexar
|
||||||
selectFilter=-- Seleccionar --
|
|
||||||
pageNum=Número de página
|
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto renombrar archivo PDF
|
||||||
|
home.auto-rename.desc=Auto renormbrar un archivo PDF según su encabezamiento detecetado
|
||||||
|
auto-rename.tags=auto-detectar,basado en el encabezamiento,organizar,re-etiquetar
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Ajustar Color/Contraste
|
||||||
|
home.adjust-contrast.desc=Ajustar Contraste, Saturación y Brillo de un PDF
|
||||||
|
adjust-contrast.tags=corrección de color,sintonizar color,modificar,mejorar
|
||||||
|
|
||||||
|
home.crop.title=Recortar PDF
|
||||||
|
home.crop.desc=Recortar un PDF para reducir su tamaño (¡conservando el texto!)
|
||||||
|
crop.tags=recortar,contraer,editar,forma
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Dividir Páginas
|
||||||
|
home.autoSplitPDF.desc=Auto Dividir PDF escaneado con código QR divsor de página escaneada físicamente
|
||||||
|
autoSplitPDF.tags=Marcado por QR,separar,segmento de escaneo,organizar
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Desinfectar
|
||||||
|
home.sanitizePdf.desc=Eliminar scripts y otros elementos de los archivos PDF
|
||||||
|
sanitizePdf.tags=limpiar,asegurar,seguro,quitar amenazas
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Página web a PDF
|
||||||
|
home.URLToPDF.desc=Convierte cualquier dirección http(s) a PDF
|
||||||
|
URLToPDF.tags=captura web,guardar página,web-a-doc,archivo
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML a PDF
|
||||||
|
home.HTMLToPDF.desc=Convierte cualquier archivo HTML o ZIP a PDF
|
||||||
|
HTMLToPDF.tags=margen,contenido web,transformación,convertir
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL a PDF
|
||||||
|
URLToPDF.header=URL a PDF
|
||||||
|
URLToPDF.submit=Convertir
|
||||||
|
URLToPDF.credit=Utiliza WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML a PDF
|
||||||
|
HTMLToPDF.header=HTML a PDF
|
||||||
|
HTMLToPDF.help=Acepta archivos HTML y ZIPs conteniendo los html/css/imágenes etc requeridas
|
||||||
|
HTMLToPDF.submit=Convertir
|
||||||
|
HTMLToPDF.credit=Utiliza WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Desinfectar archivo PDF
|
||||||
|
sanitizePDF.header=Desinfectar un archivo PDF
|
||||||
|
sanitizePDF.selectText.1=Eliminar acciones JavaScript
|
||||||
|
sanitizePDF.selectText.2=Eliminar archivos incrustados
|
||||||
|
sanitizePDF.selectText.3=Eliminar metadatos
|
||||||
|
sanitizePDF.selectText.4=Eliminar enlaces
|
||||||
|
sanitizePDF.selectText.5=Eliminar fuentes
|
||||||
|
sanitizePDF.submit=Desinfectar PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Añadir Números de Página
|
||||||
|
addPageNumbers.header=Añadir Números de Página
|
||||||
|
addPageNumbers.selectText.1=Seleccionar archivo PDF:
|
||||||
|
addPageNumbers.selectText.2=Tamaño del margen
|
||||||
|
addPageNumbers.selectText.3=Posición
|
||||||
|
addPageNumbers.selectText.4=Número de inicio
|
||||||
|
addPageNumbers.selectText.5=Páginas a numerar
|
||||||
|
addPageNumbers.selectText.6=Texto personalizado
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Añadir Números de Página
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Renombrar
|
||||||
|
auto-rename.header=Auto Renombrar PDF
|
||||||
|
auto-rename.submit=Auto Renombrar
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Ajustar Contraste
|
||||||
|
adjustContrast.header=Ajustar Contraste
|
||||||
|
adjustContrast.contrast=Contraste:
|
||||||
|
adjustContrast.brightness=Brillo:
|
||||||
|
adjustContrast.saturation=Saturación:
|
||||||
|
adjustContrast.download=Descargar
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Recortar
|
||||||
|
crop.header=Recortar Imagen
|
||||||
|
crop.submit=Entregar
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Dividir PDF
|
||||||
|
autoSplitPDF.header=Auto Dividir PDF
|
||||||
|
autoSplitPDF.description=Imprimir, Insertar, Escanear, cargar, y déjenos sepsrar automáticamente sus documentos. No se necesita clasificación manual.
|
||||||
|
autoSplitPDF.selectText.1=Imprimir algunas hojas divisorias desde la parte inferior (Blanco y negro está bien).
|
||||||
|
autoSplitPDF.selectText.2=Escanee todos sus documentos a la vez insertando la hoja divisoria entre ellos.
|
||||||
|
autoSplitPDF.selectText.3=Cargue un único archivo PDF escaneado de gran tamaño y deje que Stirling PDF se encargue del resto.
|
||||||
|
autoSplitPDF.selectText.4=Las páginas divisorias son automáticamente detectadas y eliminadas, garantizando un buen documento final.
|
||||||
|
autoSplitPDF.formPrompt=Entregar PDF conteniendo divisores de página de Stirling-PDF:
|
||||||
|
autoSplitPDF.duplexMode=Modo Dúplex (Escaneado de ambas caras)
|
||||||
|
autoSplitPDF.dividerDownload1=Descargar 'Auto Splitter Divider (mínima).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Descargar 'Auto Splitter Divider (con instrucciones).pdf'
|
||||||
|
autoSplitPDF.submit=Entregar
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Diseño de varias páginas
|
pageLayout.title=Diseño de varias páginas
|
||||||
pageLayout.header=Diseño de varias páginas
|
pageLayout.header=Diseño de varias páginas
|
||||||
pageLayout.pagesPerSheet=Páginas por hoja:
|
pageLayout.pagesPerSheet=Páginas por hoja:
|
||||||
pageLayout.submit=Entregar
|
pageLayout.submit=Entregar
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Ajustar escala de la página
|
scalePages.title=Ajustar escala de la página
|
||||||
scalePages.header=Adjustar escala de la página
|
scalePages.header=Adjustar escala de la página
|
||||||
scalePages.pageSize=Tamaño de la página del documento
|
scalePages.pageSize=Tamaño de la página del documento
|
||||||
scalePages.scaleFactor=Nivel de zoom (recorte) de la página
|
scalePages.scaleFactor=Nivel de zoom (recorte) de la página
|
||||||
scalePages.submit=Entregar
|
scalePages.submit=Entregar
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=Firma de certificado
|
certSign.title=Firma de certificado
|
||||||
certSign.header=Firmar un PDF con su certificado (Trabajo en progreso)
|
certSign.header=Firmar un PDF con su certificado (en desarrollo)
|
||||||
certSign.selectPDF=Seleccione un archivo PDF para firmar:
|
certSign.selectPDF=Seleccione un archivo PDF para firmar:
|
||||||
certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der):
|
certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der):
|
||||||
certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der):
|
certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der):
|
||||||
certSign.selectP12=Seleccione su archivo de almacén de claves PKCS#12 (.p12 o .pfx) (Opcional, si se proporciona, debe contener su clave privada y certificado):
|
certSign.selectP12=Seleccione su archivo de almacén de claves PKCS#12 (.p12 o .pfx) (Opcional, si se proporciona, debe contener su clave privada y certificado):
|
||||||
certSign.certType=Tipo de certificado
|
certSign.certType=Tipo de certificado
|
||||||
certSign.password=Ingrese su almacén de claves o contraseña de clave privada (si corresponde):
|
certSign.password=Introduzca su almacén de claves o contraseña de clave privada (si corresponde):
|
||||||
certSign.showSig=Mostrar firma
|
certSign.showSig=Mostrar firma
|
||||||
certSign.reason=Razón
|
certSign.reason=Razón
|
||||||
certSign.location=Ubicación
|
certSign.location=Ubicación
|
||||||
certSign.name=Nombre
|
certSign.name=Nombre
|
||||||
certSign.submit=Firmar PDF
|
certSign.submit=Firmar PDF
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=Eliminar espacios en blanco
|
removeBlanks.title=Eliminar espacios en blanco
|
||||||
removeBlanks.header=Eliminar páginas en blanco
|
removeBlanks.header=Eliminar páginas en blanco
|
||||||
removeBlanks.threshold=Umbral:
|
removeBlanks.threshold=Umbral:
|
||||||
@@ -175,12 +488,16 @@ removeBlanks.whitePercent=Porcentaje de blanco (%):
|
|||||||
removeBlanks.whitePercentDesc=Porcentaje de página que debe ser blanca para ser eliminada
|
removeBlanks.whitePercentDesc=Porcentaje de página que debe ser blanca para ser eliminada
|
||||||
removeBlanks.submit=Eliminar espacios en blanco
|
removeBlanks.submit=Eliminar espacios en blanco
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=Comparar
|
compare.title=Comparar
|
||||||
compare.header=Comparar archivos PDF
|
compare.header=Comparar archivos PDF
|
||||||
compare.document.1=Documento 1
|
compare.document.1=Documento 1
|
||||||
compare.document.2=Documento 2
|
compare.document.2=Documento 2
|
||||||
compare.submit=Comparar
|
compare.submit=Comparar
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=Firmar
|
sign.title=Firmar
|
||||||
sign.header=Firmar archivos PDF
|
sign.header=Firmar archivos PDF
|
||||||
sign.upload=Subir imagen
|
sign.upload=Subir imagen
|
||||||
@@ -189,14 +506,20 @@ sign.text=Entrada de texto
|
|||||||
sign.clear=Borrar
|
sign.clear=Borrar
|
||||||
sign.add=Agregar
|
sign.add=Agregar
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
repair.header=Reparar archivos PDF
|
repair.header=Reparar archivos PDF
|
||||||
repair.submit=Reparar
|
repair.submit=Reparar
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=Aplanar
|
flatten.title=Aplanar
|
||||||
flatten.header=Acoplar archivos PDF
|
flatten.header=Acoplar archivos PDF
|
||||||
flatten.submit=Aplanar
|
flatten.submit=Aplanar
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=Umbral de ángulo:
|
ScannerImageSplit.selectText.1=Umbral de ángulo:
|
||||||
ScannerImageSplit.selectText.2=Establecer el ángulo absoluto mínimo requerido para rotar la imagen (predeterminado: 10).
|
ScannerImageSplit.selectText.2=Establecer el ángulo absoluto mínimo requerido para rotar la imagen (predeterminado: 10).
|
||||||
ScannerImageSplit.selectText.3=Tolerancia:
|
ScannerImageSplit.selectText.3=Tolerancia:
|
||||||
@@ -208,18 +531,6 @@ ScannerImageSplit.selectText.8=Establecer el umbral mínimo del área de contorn
|
|||||||
ScannerImageSplit.selectText.9=Tamaño del borde:
|
ScannerImageSplit.selectText.9=Tamaño del borde:
|
||||||
ScannerImageSplit.selectText.10=Establece el tamaño del borde agregado y eliminado para evitar bordes blancos en la salida (predeterminado: 1).
|
ScannerImageSplit.selectText.10=Establece el tamaño del borde agregado y eliminado para evitar bordes blancos en la salida (predeterminado: 1).
|
||||||
|
|
||||||
navbar.settings=Ajustes
|
|
||||||
settings.title=Ajustes
|
|
||||||
settings.update=Actualización disponible
|
|
||||||
settings.appVersion=Versión de la aplicación:
|
|
||||||
settings.downloadOption.title=Elegir la opción de descarga (para descargas de un solo archivo sin ZIP):
|
|
||||||
settings.downloadOption.1=Abrir en la misma ventana
|
|
||||||
settings.downloadOption.2=Abrir en una nueva ventana
|
|
||||||
settings.downloadOption.3=Descargar el fichero
|
|
||||||
settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descargados
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / Escaneo de limpieza
|
ocr.title=OCR / Escaneo de limpieza
|
||||||
@@ -241,7 +552,7 @@ ocr.credit=Este servicio utiliza OCRmyPDF y Tesseract para OCR
|
|||||||
ocr.submit=Procesar PDF con OCR
|
ocr.submit=Procesar PDF con OCR
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=Extraer imágenes
|
extractImages.title=Extraer imágenes
|
||||||
extractImages.header=Extraer imágenes
|
extractImages.header=Extraer imágenes
|
||||||
extractImages.selectText=Seleccionar el formato de imagen para convertir las imágenes extraídas
|
extractImages.selectText=Seleccionar el formato de imagen para convertir las imágenes extraídas
|
||||||
@@ -279,32 +590,36 @@ addImage.submit=Añadir imagen
|
|||||||
#merge
|
#merge
|
||||||
merge.title=Unir
|
merge.title=Unir
|
||||||
merge.header=Unir múltiples PDFs (2+)
|
merge.header=Unir múltiples PDFs (2+)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=Unir
|
merge.submit=Unir
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=Organizador de páginas
|
pdfOrganiser.title=Organizador de páginas
|
||||||
pdfOrganiser.header=Organizador de páginas PDF
|
pdfOrganiser.header=Organizador de páginas PDF
|
||||||
pdfOrganiser.submit=Organizar páginas
|
pdfOrganiser.submit=Organizar páginas
|
||||||
|
|
||||||
#herramienta multiple
|
|
||||||
|
#multiTool
|
||||||
multiTool.title=Multi-herramienta PDF
|
multiTool.title=Multi-herramienta PDF
|
||||||
multiTool.header=Multi-herramienta PDF
|
multiTool.header=Multi-herramienta PDF
|
||||||
|
|
||||||
|
|
||||||
#pageRemover
|
#pageRemover
|
||||||
pageRemover.title=Eliminador de páginas
|
pageRemover.title=Eliminador de páginas
|
||||||
pageRemover.header=Eliminador de páginas PDF
|
pageRemover.header=Eliminador de páginas PDF
|
||||||
pageRemover.pagesToDelete=Páginas a eliminar (introducir una lista de números de página separados por coma):
|
pageRemover.pagesToDelete=Páginas a eliminar (introducir una lista de números de página separados por coma):
|
||||||
pageRemover.submit=Eliminar Páginas
|
pageRemover.submit=Eliminar Páginas
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=Rotar PDF
|
rotate.title=Rotar PDF
|
||||||
rotate.header=Rotar PDF
|
rotate.header=Rotar PDF
|
||||||
rotate.SeleccionaAngle=Seleccionar ángulo de rotación (múltiplo de 90 grados):
|
rotate.selectAngle=Select rotation angle (in multiples of 90 degrees):
|
||||||
rotate.submit=Rotar
|
rotate.submit=Rotar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=Dividir PDF
|
split.title=Dividir PDF
|
||||||
split.header=Dividir PDF
|
split.header=Dividir PDF
|
||||||
@@ -330,6 +645,7 @@ imageToPDF.selectText.3=Lógica de archivos múltiples (únicamente activado si
|
|||||||
imageToPDF.selectText.4=Unir en un único archivo PDF
|
imageToPDF.selectText.4=Unir en un único archivo PDF
|
||||||
imageToPDF.selectText.5=Convertir a PDFs separados
|
imageToPDF.selectText.5=Convertir a PDFs separados
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDF a Imagen
|
pdfToImage.title=PDF a Imagen
|
||||||
pdfToImage.header=PDF a Imagen
|
pdfToImage.header=PDF a Imagen
|
||||||
@@ -343,6 +659,7 @@ pdfToImage.grey=Escala de grises
|
|||||||
pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!)
|
pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!)
|
||||||
pdfToImage.submit=Convertir
|
pdfToImage.submit=Convertir
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=Añadir contraseña
|
addPassword.title=Añadir contraseña
|
||||||
addPassword.header=Añadir contraseña (encriptar)
|
addPassword.header=Añadir contraseña (encriptar)
|
||||||
@@ -364,6 +681,7 @@ addPassword.selectText.15=Restringe qué se puede hacer con el documento una vez
|
|||||||
addPassword.selectText.16=Restringe la apertura del propio documento
|
addPassword.selectText.16=Restringe la apertura del propio documento
|
||||||
addPassword.submit=Encriptar
|
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
|
||||||
@@ -374,14 +692,10 @@ watermark.selectText.4=Rotación (0-360):
|
|||||||
watermark.selectText.5=Ancho (Espacio entre cada marca de agua horizontalmente):
|
watermark.selectText.5=Ancho (Espacio entre cada marca de agua horizontalmente):
|
||||||
watermark.selectText.6=Alto (Espacio entre cada marca de agua verticalmente):
|
watermark.selectText.6=Alto (Espacio entre cada marca de agua verticalmente):
|
||||||
watermark.selectText.7=Opacidad (0% - 100%):
|
watermark.selectText.7=Opacidad (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=Añadir marca de agua
|
watermark.submit=Añadir marca de agua
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=Eliminar marca de agua
|
|
||||||
remove-watermark.header=Eliminar marca de agua
|
|
||||||
remove-watermark.selectText.1=Seleccionar PDF para eliminar la marca de agua:
|
|
||||||
remove-watermark.selectText.2=Texto de la marca de agua:
|
|
||||||
remove-watermark.submit=Eliminar marca de agua
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=Cambiar permisos
|
permissions.title=Cambiar permisos
|
||||||
@@ -399,6 +713,7 @@ permissions.selectText.9=Impedir imprimir
|
|||||||
permissions.selectText.10=Impedir imprimir diferentes formatos
|
permissions.selectText.10=Impedir imprimir diferentes formatos
|
||||||
permissions.submit=Cambiar
|
permissions.submit=Cambiar
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=Eliminar contraseña
|
removePassword.title=Eliminar contraseña
|
||||||
removePassword.header=Eliminar contraseña (desencriptar)
|
removePassword.header=Eliminar contraseña (desencriptar)
|
||||||
@@ -406,7 +721,9 @@ removePassword.selectText.1=Seleccionar PDF para desencriptar
|
|||||||
removePassword.selectText.2=Contraseña
|
removePassword.selectText.2=Contraseña
|
||||||
removePassword.submit=Eliminar
|
removePassword.submit=Eliminar
|
||||||
|
|
||||||
changeMetadata.title=Cambiar metadatos
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=Título:
|
||||||
changeMetadata.header=Cambiar metadatos
|
changeMetadata.header=Cambiar metadatos
|
||||||
changeMetadata.selectText.1=Editar las variables que desea cambiar
|
changeMetadata.selectText.1=Editar las variables que desea cambiar
|
||||||
changeMetadata.selectText.2=Eliminar todos los metadatos
|
changeMetadata.selectText.2=Eliminar todos los metadatos
|
||||||
@@ -424,27 +741,30 @@ changeMetadata.selectText.4=Otros Metadatos:
|
|||||||
changeMetadata.selectText.5=Agregar entrada de metadatos personalizados
|
changeMetadata.selectText.5=Agregar entrada de metadatos personalizados
|
||||||
changeMetadata.submit=Cambiar
|
changeMetadata.submit=Cambiar
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=Excel a PDF
|
xlsToPdf.title=Excel a PDF
|
||||||
xlsToPdf.header=Excel a PDF
|
xlsToPdf.header=Excel a PDF
|
||||||
xlsToPdf.selectText.1=Seleccionar hoja de cálculo de Excel XLS o XLSX para convertir
|
xlsToPdf.selectText.1=Seleccionar hoja de cálculo de Excel XLS o XLSX para convertir
|
||||||
xlsToPdf.convert=Convertir
|
xlsToPdf.convert=Convertir
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
|
||||||
pdfToPDFA.title=PDF a PDF/A
|
pdfToPDFA.title=PDF a PDF/A
|
||||||
pdfToPDFA.header=PDF a PDF/A
|
pdfToPDFA.header=PDF a PDF/A
|
||||||
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
|
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
|
||||||
pdfToPDFA.submit=Convertir
|
pdfToPDFA.submit=Convertir
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=PDF a Word
|
PDFToWord.title=PDF a Word
|
||||||
PDFToWord.header=PDF a Word
|
PDFToWord.header=PDF a Word
|
||||||
PDFToWord.selectText.1=Formato de archivo de salida
|
PDFToWord.selectText.1=Formato de archivo de salida
|
||||||
PDFToWord.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
PDFToWord.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||||
PDFToWord.submit=Convertir
|
PDFToWord.submit=Convertir
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDF a presentación
|
PDFToPresentation.title=PDF a presentación
|
||||||
PDFToPresentation.header=PDF a presentación
|
PDFToPresentation.header=PDF a presentación
|
||||||
PDFToPresentation.selectText.1=Formato de archivo de salida
|
PDFToPresentation.selectText.1=Formato de archivo de salida
|
||||||
@@ -452,6 +772,7 @@ PDFToPresentation.credit=Este servicio utiliza LibreOffice para la conversión d
|
|||||||
PDFToPresentation.submit=Convertir
|
PDFToPresentation.submit=Convertir
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
PDFToText.title=PDF a TXT/RTF
|
PDFToText.title=PDF a TXT/RTF
|
||||||
PDFToText.header=PDF a TXT/RTF
|
PDFToText.header=PDF a TXT/RTF
|
||||||
PDFToText.selectText.1=Formato de archivo de salida
|
PDFToText.selectText.1=Formato de archivo de salida
|
||||||
@@ -459,11 +780,14 @@ PDFToText.credit=Este servicio utiliza LibreOffice para la conversión de archiv
|
|||||||
PDFToText.submit=Convertir
|
PDFToText.submit=Convertir
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDF a HTML
|
PDFToHTML.title=PDF a HTML
|
||||||
PDFToHTML.header=PDF a HTML
|
PDFToHTML.header=PDF a HTML
|
||||||
PDFToHTML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
PDFToHTML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||||
PDFToHTML.submit=Convertir
|
PDFToHTML.submit=Convertir
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=PDF a XML
|
PDFToXML.title=PDF a XML
|
||||||
PDFToXML.header=PDF a XML
|
PDFToXML.header=PDF a XML
|
||||||
PDFToXML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
PDFToXML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=Hautatu PDFa(k)
|
pdfPrompt=Hautatu PDFa(k)
|
||||||
@@ -21,138 +21,449 @@ filesSelected=Hautatutako fitxategiak
|
|||||||
noFavourites=Ez dira gogokoak gehitu
|
noFavourites=Ez dira gogokoak gehitu
|
||||||
bored=Itxaroten aspertuta?
|
bored=Itxaroten aspertuta?
|
||||||
alphabet=Alfabetoa
|
alphabet=Alfabetoa
|
||||||
#############
|
downloadPdf=PDFa deskargatu
|
||||||
# HOME-PAGE #
|
text=Testua
|
||||||
#############
|
font=Letra-tipoa
|
||||||
home.desc=Zure leihatila bakarra autoostatatua zure PDF behar guztietarako
|
selectFillter=-- Select --
|
||||||
|
pageNum=Orrialde-zenbakia
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=PDF dokumentua pasahitzarekin babestuta dago eta pasahitza ez da sartu edo akastuna da
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
navbar.convert=Bihurtu
|
navbar.convert=Bihurtu
|
||||||
navbar.security=Segurtasuna
|
navbar.security=Segurtasuna
|
||||||
navbar.other=Beste bat
|
navbar.other=Beste bat
|
||||||
navbar.darkmode=Modu iluna
|
navbar.darkmode=Modu iluna
|
||||||
navbar.pageOps=Orrialde-eragiketak
|
navbar.pageOps=Orrialde-eragiketak
|
||||||
|
navbar.settings=Ezarpenak
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=Ezarpenak
|
||||||
|
settings.update=Eguneratze eskuragarria
|
||||||
|
settings.appVersion=Aplikazioaren bertsioa:
|
||||||
|
settings.downloadOption.title=Hautatu deskargatzeko aukera (fitxategi bakarra deskargatzeko ZIP gabe):
|
||||||
|
settings.downloadOption.1=Ireki leiho berean
|
||||||
|
settings.downloadOption.2=Ireki leiho berrian
|
||||||
|
settings.downloadOption.3=Deskargatu fitxategia
|
||||||
|
settings.zipThreshold=ZIP fitxategiak deskargatutako fitxategi kopurua gainditzen denean
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
|
#############
|
||||||
|
# HOME-PAGE #
|
||||||
|
#############
|
||||||
|
home.desc=Zure leihatila bakarra autoostatatua zure PDF behar guztietarako
|
||||||
|
|
||||||
|
|
||||||
home.multiTool.title=Erabilera anitzeko tresna PDF
|
home.multiTool.title=Erabilera anitzeko tresna PDF
|
||||||
home.multiTool.desc= Orriak konbinatu, biratu, berrantolatu eta ezabatu
|
home.multiTool.desc=Orriak konbinatu, biratu, berrantolatu eta ezabatu
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
||||||
|
|
||||||
home.merge.title=Elkartu
|
home.merge.title=Elkartu
|
||||||
home.merge.desc=Elkartu zenbait PDF dokumentu bakar batean modu errazean
|
home.merge.desc=Elkartu zenbait PDF dokumentu bakar batean modu errazean
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
home.split.title=Zatitu
|
home.split.title=Zatitu
|
||||||
home.split.desc=Zatitu PDFak zenbait dokumentutan
|
home.split.desc=Zatitu PDFak zenbait dokumentutan
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
home.rotate.title=Biratu
|
home.rotate.title=Biratu
|
||||||
home.rotate.desc=Biratu PDFak modu errazean
|
home.rotate.desc=Biratu PDFak modu errazean
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=Irudia PDF bihurtu
|
home.imageToPdf.title=Irudia PDF bihurtu
|
||||||
home.imageToPdf.desc=Irudi bat(PNG, JPEG, GIF)PDF bihurtu
|
home.imageToPdf.desc=Irudi bat(PNG, JPEG, GIF)PDF bihurtu
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfToImage.title=PDFa irudi bihurtu
|
home.pdfToImage.title=PDFa irudi bihurtu
|
||||||
home.pdfToImage.desc=PDF bat irudi (PNG, JPEG, GIF) bihurtu
|
home.pdfToImage.desc=PDF bat irudi (PNG, JPEG, GIF) bihurtu
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfOrganiser.title=Antolatzailea
|
home.pdfOrganiser.title=Antolatzailea
|
||||||
home.pdfOrganiser.desc=Ezabatu/Berrantolatu orrialdeak edozein ordenatan
|
home.pdfOrganiser.desc=Ezabatu/Berrantolatu orrialdeak edozein ordenatan
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=Gehitu irudia PDFari
|
home.addImage.title=Gehitu irudia PDFari
|
||||||
home.addImage.desc=Gehitu irudi bat PDFan ezarritako kokaleku batean (lanean)
|
home.addImage.desc=Gehitu irudi bat PDFan ezarritako kokaleku batean (lanean)
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
home.watermark.title=Gehitu ur-marka
|
home.watermark.title=Gehitu ur-marka
|
||||||
home.watermark.desc=Gehitu aurrez zehaztutako ur-marka bat PFD dokumentuari
|
home.watermark.desc=Gehitu aurrez zehaztutako ur-marka bat PFD dokumentuari
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
home.remove-watermark.title= Ezabatu ur-marka
|
|
||||||
home.remove-watermark.desc= Ezabatu ur-marka PDF dokumentutik
|
|
||||||
|
|
||||||
home.permissions.title=Aldatu baimenak
|
home.permissions.title=Aldatu baimenak
|
||||||
home.permissions.desc=Aldatu PDF dokumentuaren baimenak
|
home.permissions.desc=Aldatu PDF dokumentuaren baimenak
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=Ezabatu
|
home.removePages.title=Ezabatu
|
||||||
home.removePages.desc=Ezabatu nahi ez dituzun orrialdeak PDF dokumentutik
|
home.removePages.desc=Ezabatu nahi ez dituzun orrialdeak PDF dokumentutik
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
home.addPassword.title=Gehitu pasahitza
|
home.addPassword.title=Gehitu pasahitza
|
||||||
home.addPassword.desc=Enkriptatu PDF dokumentua pasahitz batekin
|
home.addPassword.desc=Enkriptatu PDF dokumentua pasahitz batekin
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
home.removePassword.title=Ezabatu pasahitza
|
home.removePassword.title=Ezabatu pasahitza
|
||||||
home.removePassword.desc=Ezabatu pasahitza PDF dokumentutik
|
home.removePassword.desc=Ezabatu pasahitza PDF dokumentutik
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
home.compressPdfs.title=Konprimatu
|
home.compressPdfs.title=Konprimatu
|
||||||
home.compressPdfs.desc=Konprimatu PDFak fitxategiaren tamaina murrizteko
|
home.compressPdfs.desc=Konprimatu PDFak fitxategiaren tamaina murrizteko
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=Aldatu metadatuak
|
home.changeMetadata.title=Aldatu metadatuak
|
||||||
home.changeMetadata.desc=Aldatu/Ezabatu/Gehitu metadatuak PDF dokumentuari
|
home.changeMetadata.desc=Aldatu/Ezabatu/Gehitu metadatuak PDF dokumentuari
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Fitxategia PDF bihurtu
|
home.fileToPDF.title=Fitxategia PDF bihurtu
|
||||||
home.fileToPDF.desc=PDF bihurtu ia edozein fitxategi (DOCX, PNG, XLS, PPT, TXT eta gehiago)
|
home.fileToPDF.desc=PDF bihurtu ia edozein fitxategi (DOCX, PNG, XLS, PPT, TXT eta gehiago)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=OCR exekutatu PDFan eta/edo garbiketa-eskaneatzeak
|
home.ocr.title=OCR exekutatu PDFan eta/edo garbiketa-eskaneatzeak
|
||||||
home.ocr.desc=Garbiketa-eskaneatzeak eta irudi-testuak detektatu PDF baten barruan eta berriz ere gehitu testu gisa
|
home.ocr.desc=Garbiketa-eskaneatzeak eta irudi-testuak detektatu PDF baten barruan eta berriz ere gehitu testu gisa
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
home.extractImages.title=Atera irudiak
|
home.extractImages.title=Atera irudiak
|
||||||
home.extractImages.desc=Atera irudi guztiak PDF batetik eta ZIPen gorde
|
home.extractImages.desc=Atera irudi guztiak PDF batetik eta ZIPen gorde
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
home.pdfToPDFA.title=PDFa PDF/A bihurtu
|
home.pdfToPDFA.title=PDFa PDF/A bihurtu
|
||||||
home.pdfToPDFA.desc=PDFa PDF/A bihurtu luzaro biltegiratzeko
|
home.pdfToPDFA.desc=PDFa PDF/A bihurtu luzaro biltegiratzeko
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
home.PDFToWord.title=PDFa Word Bihurtu
|
home.PDFToWord.title=PDFa Word Bihurtu
|
||||||
home.PDFToWord.desc=PDF formatuak Word bihurtu (DOC, DOCX y ODT)
|
home.PDFToWord.desc=PDF formatuak Word bihurtu (DOC, DOCX y ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDFa aurkezpen bihurtu
|
home.PDFToPresentation.title=PDFa aurkezpen bihurtu
|
||||||
home.PDFToPresentation.desc=PDFa aurkezpen formatu bihurtu (PPT, PPTX y ODP)
|
home.PDFToPresentation.desc=PDFa aurkezpen formatu bihurtu (PPT, PPTX y ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=PDFa TXT edo RTF bihurtu
|
home.PDFToText.title=PDFa TXT edo RTF bihurtu
|
||||||
home.PDFToText.desc=PDFa TXT edo RTF formatu bihurtu
|
home.PDFToText.desc=PDFa TXT edo RTF formatu bihurtu
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
home.PDFToHTML.title=PDFa HTML bihurtu
|
home.PDFToHTML.title=PDFa HTML bihurtu
|
||||||
home.PDFToHTML.desc=PDFa HTML formatu bihurtu
|
home.PDFToHTML.desc=PDFa HTML formatu bihurtu
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=PDFa XML bihurtu
|
home.PDFToXML.title=PDFa XML bihurtu
|
||||||
home.PDFToXML.desc=PDFa XML formatu bihurtu
|
home.PDFToXML.desc=PDFa XML formatu bihurtu
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
home.ScannerImageSplit.title=Detektatu/Zatitu argazki eskaneatuak
|
home.ScannerImageSplit.title=Detektatu/Zatitu argazki eskaneatuak
|
||||||
home.ScannerImageSplit.desc=Hainbat argazki zatitu argazki/PDF baten barruan
|
home.ScannerImageSplit.desc=Hainbat argazki zatitu argazki/PDF baten barruan
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
home.sign.title=Sinatu
|
home.sign.title=Sinatu
|
||||||
home.sign.desc=Gehitu sinadura PDFari marrazki, testu edo irudi bidez
|
home.sign.desc=Gehitu sinadura PDFari marrazki, testu edo irudi bidez
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
home.flatten.title=Lautu
|
home.flatten.title=Lautu
|
||||||
home.flatten.desc=PDF batetik elementu eta inprimaki interaktibo guztiak ezabatu
|
home.flatten.desc=PDF batetik elementu eta inprimaki interaktibo guztiak ezabatu
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
home.repair.title=Konpondu
|
home.repair.title=Konpondu
|
||||||
home.repair.desc=Saiatu PDF hondatu/kaltetu bat konpontzen
|
home.repair.desc=Saiatu PDF hondatu/kaltetu bat konpontzen
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
home.removeBlanks.title=Ezabatu orrialde zuriak
|
home.removeBlanks.title=Ezabatu orrialde zuriak
|
||||||
home.removeBlanks.desc=Detektatu orrialde zuriak eta dokumentutik ezabatu
|
home.removeBlanks.desc=Detektatu orrialde zuriak eta dokumentutik ezabatu
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
home.certSign.title=Sinatu ziurtagiriarekin
|
|
||||||
home.certSign.desc=Sinatu PDF bat Ziurtagiri/Gako batekin (PEM/P12)
|
|
||||||
|
|
||||||
home.compare.title=Konparatu
|
home.compare.title=Konparatu
|
||||||
home.compare.desc=Konparatu eta erakutsi 2 PDF dokumenturen aldeak
|
home.compare.desc=Konparatu eta erakutsi 2 PDF dokumenturen aldeak
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
|
home.certSign.title=Sinatu ziurtagiriarekin
|
||||||
|
home.certSign.desc=Sinatu PDF bat Ziurtagiri/Gako batekin (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
home.pageLayout.title=Zenbait orrialderen diseinua
|
home.pageLayout.title=Zenbait orrialderen diseinua
|
||||||
home.pageLayout.desc=Elkartu orri bakar batean PDF dokumentu baten zenbait orrialde
|
home.pageLayout.desc=Elkartu orri bakar batean PDF dokumentu baten zenbait orrialde
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
home.scalePages.title=Eskalatu/Doitu orrialdearen tamaina
|
home.scalePages.title=Eskalatu/Doitu orrialdearen tamaina
|
||||||
home.scalePages.desc=Eskalatu/Aldatu orrialde baten tamaina eta/edo edukia
|
home.scalePages.desc=Eskalatu/Aldatu orrialde baten tamaina eta/edo edukia
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
error.pdfPassword=PDF dokumentua pasahitzarekin babestuta dago eta pasahitza ez da sartu edo akastuna da
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
downloadPdf=PDFa deskargatu
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
text=Testua
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
font=Letra-tipoa
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
selectFilter=-- Hautatu --
|
|
||||||
pageNum=Orrialde-zenbakia
|
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Hainbat orrialderen diseinua
|
pageLayout.title=Hainbat orrialderen diseinua
|
||||||
pageLayout.header=Hainbat orrialderen diseinua
|
pageLayout.header=Hainbat orrialderen diseinua
|
||||||
pageLayout.pagesPerSheet=Orrialdeak orriko:
|
pageLayout.pagesPerSheet=Orrialdeak orriko:
|
||||||
pageLayout.submit=Entregatu
|
pageLayout.submit=Entregatu
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Doitu orrialdearen eskala
|
scalePages.title=Doitu orrialdearen eskala
|
||||||
scalePages.header=Doitu orrialdearen eskala
|
scalePages.header=Doitu orrialdearen eskala
|
||||||
scalePages.pageSize=Dokumentuaren orrialdearen tamaina
|
scalePages.pageSize=Dokumentuaren orrialdearen tamaina
|
||||||
scalePages.scaleFactor=Orriaren zoom maila (moztea)
|
scalePages.scaleFactor=Orriaren zoom maila (moztea)
|
||||||
scalePages.submit=Entregatu
|
scalePages.submit=Entregatu
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=Ziurtagiriaren sinadura
|
certSign.title=Ziurtagiriaren sinadura
|
||||||
certSign.header=Sinatu PDF bat haren ziurtagiriarekin (lanean)
|
certSign.header=Sinatu PDF bat haren ziurtagiriarekin (lanean)
|
||||||
certSign.selectPDF=Hautatu PDF fitxategi bat sinatzeko:
|
certSign.selectPDF=Hautatu PDF fitxategi bat sinatzeko:
|
||||||
@@ -167,6 +478,8 @@ certSign.location=Kokalekua
|
|||||||
certSign.name=Izena
|
certSign.name=Izena
|
||||||
certSign.submit=Sinatu PDFa
|
certSign.submit=Sinatu PDFa
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=Ezabatu zuriuneak
|
removeBlanks.title=Ezabatu zuriuneak
|
||||||
removeBlanks.header=Ezabatu orrialde zuriak
|
removeBlanks.header=Ezabatu orrialde zuriak
|
||||||
removeBlanks.threshold=Gutxieneko balioa:
|
removeBlanks.threshold=Gutxieneko balioa:
|
||||||
@@ -175,12 +488,16 @@ removeBlanks.whitePercent=Zuriaren protzentajea (%):
|
|||||||
removeBlanks.whitePercentDesc=Zuria izan behar den orriaren ehunekoa ezabatua izan dadin
|
removeBlanks.whitePercentDesc=Zuria izan behar den orriaren ehunekoa ezabatua izan dadin
|
||||||
removeBlanks.submit=Ezabatu zuriuneak
|
removeBlanks.submit=Ezabatu zuriuneak
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=Konparatu
|
compare.title=Konparatu
|
||||||
compare.header=Konparatu PDF fitxategiak
|
compare.header=Konparatu PDF fitxategiak
|
||||||
compare.document.1=1. dokumentua
|
compare.document.1=1. dokumentua
|
||||||
compare.document.2=2. dokumentua
|
compare.document.2=2. dokumentua
|
||||||
compare.submit=Konparatu
|
compare.submit=Konparatu
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=Sinatu
|
sign.title=Sinatu
|
||||||
sign.header=Sinatu PDF fitxategiak
|
sign.header=Sinatu PDF fitxategiak
|
||||||
sign.upload=Igo irudia
|
sign.upload=Igo irudia
|
||||||
@@ -189,14 +506,20 @@ sign.text=Testua sartzea
|
|||||||
sign.clear=Garbitu
|
sign.clear=Garbitu
|
||||||
sign.add=Gehitu
|
sign.add=Gehitu
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=Konpondu
|
repair.title=Konpondu
|
||||||
repair.header=Konpondu PDF fitxategiak
|
repair.header=Konpondu PDF fitxategiak
|
||||||
repair.submit=Konpondu
|
repair.submit=Konpondu
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=Lautu
|
flatten.title=Lautu
|
||||||
flatten.header=Akoplatu PDF fitxategiak
|
flatten.header=Akoplatu PDF fitxategiak
|
||||||
flatten.submit=Lautu
|
flatten.submit=Lautu
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=Angeluaren gutxieneko balioa:
|
ScannerImageSplit.selectText.1=Angeluaren gutxieneko balioa:
|
||||||
ScannerImageSplit.selectText.2=Ezarri eskatutako gutxieneko angelu absolutua irudia biratzeko (lehenetsia: 10).
|
ScannerImageSplit.selectText.2=Ezarri eskatutako gutxieneko angelu absolutua irudia biratzeko (lehenetsia: 10).
|
||||||
ScannerImageSplit.selectText.3=Tolerantzia:
|
ScannerImageSplit.selectText.3=Tolerantzia:
|
||||||
@@ -208,18 +531,6 @@ ScannerImageSplit.selectText.8=Ezarri inguruko arearen gutxieneko balioa argazki
|
|||||||
ScannerImageSplit.selectText.9=Ertzaren tamaina:
|
ScannerImageSplit.selectText.9=Ertzaren tamaina:
|
||||||
ScannerImageSplit.selectText.10=Ezarri gehitutako eta ezabatutako ertzaren tamaina irteeran ertz zuriak saihesteko (lehenetsia: 1).
|
ScannerImageSplit.selectText.10=Ezarri gehitutako eta ezabatutako ertzaren tamaina irteeran ertz zuriak saihesteko (lehenetsia: 1).
|
||||||
|
|
||||||
navbar.settings=Ezarpenak
|
|
||||||
settings.title=Ezarpenak
|
|
||||||
settings.update=Eguneratze eskuragarria
|
|
||||||
settings.appVersion=Aplikazioaren bertsioa:
|
|
||||||
settings.downloadOption.title=Hautatu deskargatzeko aukera (fitxategi bakarra deskargatzeko ZIP gabe):
|
|
||||||
settings.downloadOption.1=Ireki leiho berean
|
|
||||||
settings.downloadOption.2=Ireki leiho berrian
|
|
||||||
settings.downloadOption.3=Deskargatu fitxategia
|
|
||||||
settings.zipThreshold=ZIP fitxategiak deskargatutako fitxategi kopurua gainditzen denean
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / Garbiketa-eskaneatzea
|
ocr.title=OCR / Garbiketa-eskaneatzea
|
||||||
@@ -241,7 +552,7 @@ ocr.credit=Zerbitzu honek OCRmyPDF eta OCR-rako Tesseract erabiltzen ditu
|
|||||||
ocr.submit=PDF prozesatu OCR-rekin
|
ocr.submit=PDF prozesatu OCR-rekin
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=Atera irudiak
|
extractImages.title=Atera irudiak
|
||||||
extractImages.header=Atera irudiak
|
extractImages.header=Atera irudiak
|
||||||
extractImages.selectText=Hautatu irudi-formatua ateratako irudiak bihurtzeko
|
extractImages.selectText=Hautatu irudi-formatua ateratako irudiak bihurtzeko
|
||||||
@@ -279,32 +590,36 @@ addImage.submit=Gehitu irudia
|
|||||||
#merge
|
#merge
|
||||||
merge.title=Elkartu
|
merge.title=Elkartu
|
||||||
merge.header=Elkartu zenbait PDF (2+)
|
merge.header=Elkartu zenbait PDF (2+)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=Elkartu
|
merge.submit=Elkartu
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=Orrialdeen antolatzailea
|
pdfOrganiser.title=Orrialdeen antolatzailea
|
||||||
pdfOrganiser.header=PDF orrialdeen antolatzailea
|
pdfOrganiser.header=PDF orrialdeen antolatzailea
|
||||||
pdfOrganiser.submit=Antolatu orrialdeak
|
pdfOrganiser.submit=Antolatu orrialdeak
|
||||||
|
|
||||||
#herramienta multiple
|
|
||||||
multiTool.title= PDF erabilera anitzeko tresna
|
#multiTool
|
||||||
|
multiTool.title=PDF erabilera anitzeko tresna
|
||||||
multiTool.header=PDF erabilera anitzeko tresna
|
multiTool.header=PDF erabilera anitzeko tresna
|
||||||
|
|
||||||
|
|
||||||
#pageRemover
|
#pageRemover
|
||||||
pageRemover.title=Orrialdeen ezabatzailea
|
pageRemover.title=Orrialdeen ezabatzailea
|
||||||
pageRemover.header=PDF orrialdeen ezabatzailea
|
pageRemover.header=PDF orrialdeen ezabatzailea
|
||||||
pageRemover.pagesToDelete=Ezabatu beharreko orrialdeak (sartu komaz bereizitako orrialde-zenbakien zerrenda):
|
pageRemover.pagesToDelete=Ezabatu beharreko orrialdeak (sartu komaz bereizitako orrialde-zenbakien zerrenda):
|
||||||
pageRemover.submit=Ezabatu orrialdeak
|
pageRemover.submit=Ezabatu orrialdeak
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=Biratu PDFa
|
rotate.title=Biratu PDFa
|
||||||
rotate.header=Biratu PDFa
|
rotate.header=Biratu PDFa
|
||||||
rotate.SeleccionaAngle=Hautatu errotazio-angelua (90 graduren multiploa):
|
rotate.selectAngle=Select rotation angle (in multiples of 90 degrees):
|
||||||
rotate.submit=Biratu
|
rotate.submit=Biratu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=Zatitu PDFa
|
split.title=Zatitu PDFa
|
||||||
split.header=Zatitu PDFa
|
split.header=Zatitu PDFa
|
||||||
@@ -330,6 +645,7 @@ imageToPDF.selectText.3=Fitxategi askoren logika (gaituta bakarrik zenbait irudi
|
|||||||
imageToPDF.selectText.4=Elkartu PDF bakar batean
|
imageToPDF.selectText.4=Elkartu PDF bakar batean
|
||||||
imageToPDF.selectText.5=Bihurtu eta PDF bereizituak sortu
|
imageToPDF.selectText.5=Bihurtu eta PDF bereizituak sortu
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDFa irudi bihurtu
|
pdfToImage.title=PDFa irudi bihurtu
|
||||||
pdfToImage.header=PDFa irudi bihurtu
|
pdfToImage.header=PDFa irudi bihurtu
|
||||||
@@ -343,6 +659,7 @@ pdfToImage.grey=Gris-eskala
|
|||||||
pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!)
|
pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!)
|
||||||
pdfToImage.submit=Bihurtu
|
pdfToImage.submit=Bihurtu
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=Gehitu pasahitza
|
addPassword.title=Gehitu pasahitza
|
||||||
addPassword.header=Gehitu pasahitza (enkriptatu)
|
addPassword.header=Gehitu pasahitza (enkriptatu)
|
||||||
@@ -364,6 +681,7 @@ addPassword.selectText.15=Mugatu zer egin daitekeen dokumentuarekin behin zabald
|
|||||||
addPassword.selectText.16=Mugatu dokumentu bera zabaltzeko aukera
|
addPassword.selectText.16=Mugatu dokumentu bera zabaltzeko aukera
|
||||||
addPassword.submit=Enkriptatu
|
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
|
||||||
@@ -374,14 +692,10 @@ watermark.selectText.4=Errotazioa (0-360):
|
|||||||
watermark.selectText.5=Zabalera (ur-marka bakoitzaren arteko espazioa horizontalean):
|
watermark.selectText.5=Zabalera (ur-marka bakoitzaren arteko espazioa horizontalean):
|
||||||
watermark.selectText.6=Altuera (ur-marka bakoitzaren arteko espazioa bertikalean):
|
watermark.selectText.6=Altuera (ur-marka bakoitzaren arteko espazioa bertikalean):
|
||||||
watermark.selectText.7=Opakutasuna (0% - 100%):
|
watermark.selectText.7=Opakutasuna (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=Gehitu ur-marka
|
watermark.submit=Gehitu ur-marka
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=Ezabatu ur-marka
|
|
||||||
remove-watermark.header=Ezabatu ur-marka
|
|
||||||
remove-watermark.selectText.1=Hautatu PDFa ur-marka ezabatzeko:
|
|
||||||
remove-watermark.selectText.2=Ur-markaren testua:
|
|
||||||
remove-watermark.submit=Ezabatu ur-marka
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=Aldatu baimenak
|
permissions.title=Aldatu baimenak
|
||||||
@@ -399,6 +713,7 @@ permissions.selectText.9=Galarazi inprimatzea
|
|||||||
permissions.selectText.10=Galarazi zenbait formatu inprimatzea
|
permissions.selectText.10=Galarazi zenbait formatu inprimatzea
|
||||||
permissions.submit=Aldatu
|
permissions.submit=Aldatu
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=Ezabatu pasahitza
|
removePassword.title=Ezabatu pasahitza
|
||||||
removePassword.header=Ezabatu pasahitza (desenkriptatu)
|
removePassword.header=Ezabatu pasahitza (desenkriptatu)
|
||||||
@@ -406,7 +721,9 @@ removePassword.selectText.1=Hautatu PDFa desenkriptatzeko
|
|||||||
removePassword.selectText.2=Pasahitza
|
removePassword.selectText.2=Pasahitza
|
||||||
removePassword.submit=Ezabatu
|
removePassword.submit=Ezabatu
|
||||||
|
|
||||||
changeMetadata.title=Aldatu metadatuak
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=Izenburua:
|
||||||
changeMetadata.header=Aldatu metadatuak
|
changeMetadata.header=Aldatu metadatuak
|
||||||
changeMetadata.selectText.1=Editatu aldatu nahi dituzun aldagaiak
|
changeMetadata.selectText.1=Editatu aldatu nahi dituzun aldagaiak
|
||||||
changeMetadata.selectText.2=Ezabatu metadatu guztiak
|
changeMetadata.selectText.2=Ezabatu metadatu guztiak
|
||||||
@@ -424,27 +741,30 @@ changeMetadata.selectText.4=Beste metadatu batzuk:
|
|||||||
changeMetadata.selectText.5=Gehitu metadatu pertsonalizatuen sarrera
|
changeMetadata.selectText.5=Gehitu metadatu pertsonalizatuen sarrera
|
||||||
changeMetadata.submit=Aldatu
|
changeMetadata.submit=Aldatu
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=Excela PDF bihurtu
|
xlsToPdf.title=Excela PDF bihurtu
|
||||||
xlsToPdf.header=Excela PDF bihurtu
|
xlsToPdf.header=Excela PDF bihurtu
|
||||||
xlsToPdf.selectText.1=Hautatu Excel XLSren edo XLSXren kalkulu-orria bihurtzeko
|
xlsToPdf.selectText.1=Hautatu Excel XLSren edo XLSXren kalkulu-orria bihurtzeko
|
||||||
xlsToPdf.convert=Bikurtu
|
xlsToPdf.convert=Bikurtu
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
|
||||||
pdfToPDFA.title=PDFa PDF/A bihurtu
|
pdfToPDFA.title=PDFa PDF/A bihurtu
|
||||||
pdfToPDFA.header=PDFa PDF/A bihurtu
|
pdfToPDFA.header=PDFa PDF/A bihurtu
|
||||||
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
|
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
|
||||||
pdfToPDFA.submit=Bihurtu
|
pdfToPDFA.submit=Bihurtu
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=PDFa Word bihurtu
|
PDFToWord.title=PDFa Word bihurtu
|
||||||
PDFToWord.header=PDFa Word bihurtu
|
PDFToWord.header=PDFa Word bihurtu
|
||||||
PDFToWord.selectText.1=Irteerako fitxategiaren formatua
|
PDFToWord.selectText.1=Irteerako fitxategiaren formatua
|
||||||
PDFToWord.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
PDFToWord.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||||
PDFToWord.submit=Bihurtu
|
PDFToWord.submit=Bihurtu
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDFa aurkezpen bihurtu
|
PDFToPresentation.title=PDFa aurkezpen bihurtu
|
||||||
PDFToPresentation.header=PDFa aurkezpen bihurtu
|
PDFToPresentation.header=PDFa aurkezpen bihurtu
|
||||||
PDFToPresentation.selectText.1=Irteerako fitxategiaren formatua
|
PDFToPresentation.selectText.1=Irteerako fitxategiaren formatua
|
||||||
@@ -452,6 +772,7 @@ PDFToPresentation.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bi
|
|||||||
PDFToPresentation.submit=Bihurtu
|
PDFToPresentation.submit=Bihurtu
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
PDFToText.title=PDFa TXT/RTF bihurtu
|
PDFToText.title=PDFa TXT/RTF bihurtu
|
||||||
PDFToText.header=PDFa TXT/RTF bihurtu
|
PDFToText.header=PDFa TXT/RTF bihurtu
|
||||||
PDFToText.selectText.1=Irteerako fitxategiaren formatua
|
PDFToText.selectText.1=Irteerako fitxategiaren formatua
|
||||||
@@ -459,11 +780,14 @@ PDFToText.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
|||||||
PDFToText.submit=Bihurtu
|
PDFToText.submit=Bihurtu
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDFa HTML bihurtu
|
PDFToHTML.title=PDFa HTML bihurtu
|
||||||
PDFToHTML.header=PDFa HTML bihurtu
|
PDFToHTML.header=PDFa HTML bihurtu
|
||||||
PDFToHTML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
PDFToHTML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||||
PDFToHTML.submit=Bihurtu
|
PDFToHTML.submit=Bihurtu
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=PDFa XML bihurtu
|
PDFToXML.title=PDFa XML bihurtu
|
||||||
PDFToXML.header=PDFa XML bihurtu
|
PDFToXML.header=PDFa XML bihurtu
|
||||||
PDFToXML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
PDFToXML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=Scegli PDF
|
pdfPrompt=Scegli PDF
|
||||||
@@ -21,139 +21,449 @@ filesSelected=file selezionati
|
|||||||
noFavourites=Nessun preferito
|
noFavourites=Nessun preferito
|
||||||
bored=Stanco di aspettare?
|
bored=Stanco di aspettare?
|
||||||
alphabet=Alfabeto
|
alphabet=Alfabeto
|
||||||
|
downloadPdf=Scarica PDF
|
||||||
|
text=Testo
|
||||||
|
font=Font
|
||||||
|
selectFillter=-- Seleziona --
|
||||||
|
pageNum=Numero pagina
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
|
navbar.convert=Converti
|
||||||
|
navbar.security=Sicurezza
|
||||||
|
navbar.other=Altro
|
||||||
|
navbar.darkmode=Modalità Scura
|
||||||
|
navbar.pageOps=Modifica pagine
|
||||||
|
navbar.settings=Impostazioni
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=Impostazioni
|
||||||
|
settings.update=Aggiornamento disponibile
|
||||||
|
settings.appVersion=Versione App:
|
||||||
|
settings.downloadOption.title=Scegli opzione di download (Per file singoli non compressi):
|
||||||
|
settings.downloadOption.1=Apri in questa finestra
|
||||||
|
settings.downloadOption.2=Apri in una nuova finestra
|
||||||
|
settings.downloadOption.3=Scarica file
|
||||||
|
settings.zipThreshold=Comprimi file in .zip quando il numero di download supera
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
#############
|
#############
|
||||||
home.desc=La tua pagina self-hostata per gestire qualsiasi PDF.
|
home.desc=La tua pagina self-hostata per gestire qualsiasi PDF.
|
||||||
|
|
||||||
|
|
||||||
navbar.convert=Converti
|
|
||||||
navbar.security=Sicurezza
|
|
||||||
navbar.other=Altro
|
|
||||||
navbar.darkmode=Modalità Scura
|
|
||||||
navbar.pageOps=Modifica pagine
|
|
||||||
|
|
||||||
home.multiTool.title=Multifunzione PDF
|
home.multiTool.title=Multifunzione PDF
|
||||||
home.multiTool.desc=Unisci, Ruota, Riordina, e Rimuovi pagine
|
home.multiTool.desc=Unisci, Ruota, Riordina, e Rimuovi pagine
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
||||||
|
|
||||||
home.merge.title=Unisci
|
home.merge.title=Unisci
|
||||||
home.merge.desc=Unisci facilmente più PDF in uno.
|
home.merge.desc=Unisci facilmente più PDF in uno.
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
home.split.title=Dividi
|
home.split.title=Dividi
|
||||||
home.split.desc=Dividi un singolo PDF in più documenti.
|
home.split.desc=Dividi un singolo PDF in più documenti.
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
home.rotate.title=Ruota
|
home.rotate.title=Ruota
|
||||||
home.rotate.desc=Ruota un PDF.
|
home.rotate.desc=Ruota un PDF.
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=Da immagine a PDF
|
home.imageToPdf.title=Da immagine a PDF
|
||||||
home.imageToPdf.desc=Converti un'immagine (PNG, JPEG, GIF) in PDF.
|
home.imageToPdf.desc=Converti un'immagine (PNG, JPEG, GIF) in PDF.
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfToImage.title=Da PDF a immagine
|
home.pdfToImage.title=Da PDF a immagine
|
||||||
home.pdfToImage.desc=Converti un PDF in un'immagine. (PNG, JPEG, GIF)
|
home.pdfToImage.desc=Converti un PDF in un'immagine. (PNG, JPEG, GIF)
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfOrganiser.title=Organizza
|
home.pdfOrganiser.title=Organizza
|
||||||
home.pdfOrganiser.desc=Rimuovi/Riordina le pagine in qualsiasi ordine.
|
home.pdfOrganiser.desc=Rimuovi/Riordina le pagine in qualsiasi ordine.
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=Aggiungi Immagine
|
home.addImage.title=Aggiungi Immagine
|
||||||
home.addImage.desc=Aggiungi un'immagine in un punto specifico del PDF (Work in progress)
|
home.addImage.desc=Aggiungi un'immagine in un punto specifico del PDF (Work in progress)
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
home.watermark.title=Aggiungi Filigrana
|
home.watermark.title=Aggiungi Filigrana
|
||||||
home.watermark.desc=Aggiungi una filigrana al tuo PDF.
|
home.watermark.desc=Aggiungi una filigrana al tuo PDF.
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
home.remove-watermark.title=Rimuovi Filigrana
|
|
||||||
home.remove-watermark.desc=Rimuovi la filigrana dal tuo PDF.
|
|
||||||
|
|
||||||
home.permissions.title=Cambia Permessi
|
home.permissions.title=Cambia Permessi
|
||||||
home.permissions.desc=Cambia i permessi del tuo PDF.
|
home.permissions.desc=Cambia i permessi del tuo PDF.
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=Rimuovi
|
home.removePages.title=Rimuovi
|
||||||
home.removePages.desc=Elimina alcune pagine dal PDF.
|
home.removePages.desc=Elimina alcune pagine dal PDF.
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
home.addPassword.title=Aggiungi Password
|
home.addPassword.title=Aggiungi Password
|
||||||
home.addPassword.desc=Crittografa il tuo PDF con una password.
|
home.addPassword.desc=Crittografa il tuo PDF con una password.
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
home.removePassword.title=Rimuovi Password
|
home.removePassword.title=Rimuovi Password
|
||||||
home.removePassword.desc=Rimuovi la password dal tuo PDF.
|
home.removePassword.desc=Rimuovi la password dal tuo PDF.
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
home.compressPdfs.title=Comprimi
|
home.compressPdfs.title=Comprimi
|
||||||
home.compressPdfs.desc=Comprimi PDF per ridurne le dimensioni.
|
home.compressPdfs.desc=Comprimi PDF per ridurne le dimensioni.
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=Modifica Proprietà
|
home.changeMetadata.title=Modifica Proprietà
|
||||||
home.changeMetadata.desc=Modifica/Aggiungi/Rimuovi le proprietà di un documento PDF.
|
home.changeMetadata.desc=Modifica/Aggiungi/Rimuovi le proprietà di un documento PDF.
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Converti file in PDF
|
home.fileToPDF.title=Converti file in PDF
|
||||||
home.fileToPDF.desc=Converti quasi ogni file in PDF (DOCX, PNG, XLS, PPT, TXT e altro)
|
home.fileToPDF.desc=Converti quasi ogni file in PDF (DOCX, PNG, XLS, PPT, TXT e altro)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=OCR / Pulisci scansioni
|
home.ocr.title=OCR / Pulisci scansioni
|
||||||
home.ocr.desc=Pulisci scansioni ed estrai testo da immagini, convertendo le immagini in testo puro.
|
home.ocr.desc=Pulisci scansioni ed estrai testo da immagini, convertendo le immagini in testo puro.
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
home.extractImages.title=Estrai immagini
|
home.extractImages.title=Estrai immagini
|
||||||
home.extractImages.desc=Estrai tutte le immagini da un PDF e salvale come zip.
|
home.extractImages.desc=Estrai tutte le immagini da un PDF e salvale come zip.
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
home.pdfToPDFA.title=Converti in PDF/A
|
home.pdfToPDFA.title=Converti in PDF/A
|
||||||
home.pdfToPDFA.desc=Converti un PDF nel formato PDF/A per archiviazione a lungo termine.
|
home.pdfToPDFA.desc=Converti un PDF nel formato PDF/A per archiviazione a lungo termine.
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
home.PDFToWord.title=Da PDF a Word
|
home.PDFToWord.title=Da PDF a Word
|
||||||
home.PDFToWord.desc=Converti un PDF nei formati Word (DOC, DOCX e ODT)
|
home.PDFToWord.desc=Converti un PDF nei formati Word (DOC, DOCX e ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
home.PDFToPresentation.title=Da PDF a presentazioni
|
home.PDFToPresentation.title=Da PDF a presentazioni
|
||||||
home.PDFToPresentation.desc=Converti un PDF in presentazioni (PPT, PPTX and ODP)
|
home.PDFToPresentation.desc=Converti un PDF in presentazioni (PPT, PPTX and ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=Da PDF a testo/RTF
|
home.PDFToText.title=Da PDF a testo/RTF
|
||||||
home.PDFToText.desc=Converti un PDF in testo o RTF.
|
home.PDFToText.desc=Converti un PDF in testo o RTF.
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
home.PDFToHTML.title=Da PDF ad HTML
|
home.PDFToHTML.title=Da PDF ad HTML
|
||||||
home.PDFToHTML.desc=Converti un PDF in HTML.
|
home.PDFToHTML.desc=Converti un PDF in HTML.
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=Da PDF a XML
|
home.PDFToXML.title=Da PDF a XML
|
||||||
home.PDFToXML.desc=Converti un PDF in XML.
|
home.PDFToXML.desc=Converti un PDF in XML.
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
home.ScannerImageSplit.title=Trova/Dividi foto scansionate
|
home.ScannerImageSplit.title=Trova/Dividi foto scansionate
|
||||||
home.ScannerImageSplit.desc=Estrai più foto da una singola foto o PDF.
|
home.ScannerImageSplit.desc=Estrai più foto da una singola foto o PDF.
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
home.sign.title=Firma
|
home.sign.title=Firma
|
||||||
home.sign.desc=Aggiungi una firma al PDF da disegno, testo o immagine.
|
home.sign.desc=Aggiungi una firma al PDF da disegno, testo o immagine.
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
home.flatten.title=Appiattisci
|
home.flatten.title=Appiattisci
|
||||||
home.flatten.desc=Rimuovi tutti gli elementi interattivi e moduli da un PDF.
|
home.flatten.desc=Rimuovi tutti gli elementi interattivi e moduli da un PDF.
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
home.repair.title=Ripara
|
home.repair.title=Ripara
|
||||||
home.repair.desc=Prova a riparare un PDF corrotto.
|
home.repair.desc=Prova a riparare un PDF corrotto.
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
home.removeBlanks.title=Rimuovi pagine vuote
|
home.removeBlanks.title=Rimuovi pagine vuote
|
||||||
home.removeBlanks.desc=Trova e rimuovi pagine vuote da un PDF.
|
home.removeBlanks.desc=Trova e rimuovi pagine vuote da un PDF.
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
home.certSign.title=Sign with Certificate
|
|
||||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
|
||||||
|
|
||||||
home.compare.title=Compara
|
home.compare.title=Compara
|
||||||
home.compare.desc=Vedi e compara le differenze tra due PDF.
|
home.compare.desc=Vedi e compara le differenze tra due PDF.
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
|
home.certSign.title=Sign with Certificate
|
||||||
|
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
home.pageLayout.title=Multi-Page Layout
|
home.pageLayout.title=Multi-Page Layout
|
||||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
home.scalePages.title=Adjust page size/scale
|
home.scalePages.title=Adjust page size/scale
|
||||||
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
downloadPdf=Scarica PDF
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
text=Testo
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
font=Font
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
selectFillter=-- Seleziona --
|
|
||||||
pageNum=Numero pagina
|
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Multi Page Layout
|
pageLayout.title=Multi Page Layout
|
||||||
pageLayout.header=Multi Page Layout
|
pageLayout.header=Multi Page Layout
|
||||||
pageLayout.pagesPerSheet=Pages per sheet:
|
pageLayout.pagesPerSheet=Pages per sheet:
|
||||||
pageLayout.submit=Submit
|
pageLayout.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Adjust page-scale
|
scalePages.title=Adjust page-scale
|
||||||
scalePages.header=Adjust page-scale
|
scalePages.header=Adjust page-scale
|
||||||
scalePages.pageSize=Size of a page of the document.
|
scalePages.pageSize=Size of a page of the document.
|
||||||
scalePages.scaleFactor=Zoom level (crop) of a page.
|
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||||
scalePages.submit=Submit
|
scalePages.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=Firma del certificato
|
certSign.title=Firma del certificato
|
||||||
certSign.header=Firma un PDF con il tuo certificato (Lavoro in corso)
|
certSign.header=Firma un PDF con il tuo certificato (Lavoro in corso)
|
||||||
certSign.selectPDF=Seleziona un file PDF per la firma:
|
certSign.selectPDF=Seleziona un file PDF per la firma:
|
||||||
@@ -168,6 +478,8 @@ certSign.location=Posizione
|
|||||||
certSign.name=Nome
|
certSign.name=Nome
|
||||||
certSign.submit=Firma PDF
|
certSign.submit=Firma PDF
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=Rimuovi spazi vuoti
|
removeBlanks.title=Rimuovi spazi vuoti
|
||||||
removeBlanks.header=Rimuovi pagine vuote
|
removeBlanks.header=Rimuovi pagine vuote
|
||||||
removeBlanks.threshold=Soglia:
|
removeBlanks.threshold=Soglia:
|
||||||
@@ -176,12 +488,16 @@ removeBlanks.whitePercent=Percentuale di bianco (%):
|
|||||||
removeBlanks.whitePercentDesc=Percentuale della pagina che deve essere bianca per venire rimossa
|
removeBlanks.whitePercentDesc=Percentuale della pagina che deve essere bianca per venire rimossa
|
||||||
removeBlanks.submit=Rimuovi
|
removeBlanks.submit=Rimuovi
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=Compara
|
compare.title=Compara
|
||||||
compare.header=Compara PDF
|
compare.header=Compara PDF
|
||||||
compare.document.1=Documento 1
|
compare.document.1=Documento 1
|
||||||
compare.document.2=Documento 2
|
compare.document.2=Documento 2
|
||||||
compare.submit=Compara
|
compare.submit=Compara
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=Firma
|
sign.title=Firma
|
||||||
sign.header=Firma PDF
|
sign.header=Firma PDF
|
||||||
sign.upload=Carica immagine
|
sign.upload=Carica immagine
|
||||||
@@ -190,14 +506,20 @@ sign.text=Testo
|
|||||||
sign.clear=Cancella
|
sign.clear=Cancella
|
||||||
sign.add=Aggiungi
|
sign.add=Aggiungi
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=Ripara
|
repair.title=Ripara
|
||||||
repair.header=Ripara PDF
|
repair.header=Ripara PDF
|
||||||
repair.submit=Ripara
|
repair.submit=Ripara
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=Appiattisci
|
flatten.title=Appiattisci
|
||||||
flatten.header=Appiattisci PDF
|
flatten.header=Appiattisci PDF
|
||||||
flatten.submit=Appiattisci
|
flatten.submit=Appiattisci
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=Soglia angolo:
|
ScannerImageSplit.selectText.1=Soglia angolo:
|
||||||
ScannerImageSplit.selectText.2=Imposta il minimo angolo richiesto perché l'immagine venga ruotata (default: 10).
|
ScannerImageSplit.selectText.2=Imposta il minimo angolo richiesto perché l'immagine venga ruotata (default: 10).
|
||||||
ScannerImageSplit.selectText.3=Tolleranza:
|
ScannerImageSplit.selectText.3=Tolleranza:
|
||||||
@@ -209,19 +531,6 @@ ScannerImageSplit.selectText.8=Imposta l'area minima del contorno di una foto
|
|||||||
ScannerImageSplit.selectText.9=Spessore bordo:
|
ScannerImageSplit.selectText.9=Spessore bordo:
|
||||||
ScannerImageSplit.selectText.10=Imposta lo spessore del bordo aggiunto o rimosso per prevenire bordi bianchi nel risultato (default: 1).
|
ScannerImageSplit.selectText.10=Imposta lo spessore del bordo aggiunto o rimosso per prevenire bordi bianchi nel risultato (default: 1).
|
||||||
|
|
||||||
navbar.settings=Impostazioni
|
|
||||||
settings.title=Impostazioni
|
|
||||||
settings.update=Aggiornamento disponibile
|
|
||||||
settings.appVersion=Versione App:
|
|
||||||
settings.downloadOption.title=Scegli opzione di download (Per file singoli non compressi):
|
|
||||||
settings.downloadOption.1=Apri in questa finestra
|
|
||||||
settings.downloadOption.2=Apri in una nuova finestra
|
|
||||||
settings.downloadOption.3=Scarica file
|
|
||||||
settings.zipThreshold=Comprimi file in .zip quando il numero di download supera
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / Pulisci scansioni
|
ocr.title=OCR / Pulisci scansioni
|
||||||
@@ -243,7 +552,7 @@ ocr.credit=Questo servizio utilizza OCRmyPDF e Tesseract per l'OCR.
|
|||||||
ocr.submit=Scansiona testo nel PDF con OCR
|
ocr.submit=Scansiona testo nel PDF con OCR
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=Estrai immagini
|
extractImages.title=Estrai immagini
|
||||||
extractImages.header=Estrai immagini
|
extractImages.header=Estrai immagini
|
||||||
extractImages.selectText=Seleziona il formato in cui salvare le immagini estratte
|
extractImages.selectText=Seleziona il formato in cui salvare le immagini estratte
|
||||||
@@ -269,6 +578,7 @@ compress.selectText.4=Modalità automatica - Regola automaticamente la qualità
|
|||||||
compress.selectText.5=Dimensioni PDF previste (ad es. 25 MB, 10,8 MB, 25 KB)
|
compress.selectText.5=Dimensioni PDF previste (ad es. 25 MB, 10,8 MB, 25 KB)
|
||||||
compress.submit=Comprimi
|
compress.submit=Comprimi
|
||||||
|
|
||||||
|
|
||||||
#Add image
|
#Add image
|
||||||
addImage.title=Aggiungi Immagine
|
addImage.title=Aggiungi Immagine
|
||||||
addImage.header=Aggiungi un'immagine ad un PDF
|
addImage.header=Aggiungi un'immagine ad un PDF
|
||||||
@@ -280,13 +590,17 @@ addImage.submit=Aggiungi immagine
|
|||||||
#merge
|
#merge
|
||||||
merge.title=Unisci
|
merge.title=Unisci
|
||||||
merge.header=Unisci 2 o più PDF
|
merge.header=Unisci 2 o più PDF
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=Unisci
|
merge.submit=Unisci
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=Organizza pagine
|
pdfOrganiser.title=Organizza pagine
|
||||||
pdfOrganiser.header=Organizza le pagine di un PDF
|
pdfOrganiser.header=Organizza le pagine di un PDF
|
||||||
pdfOrganiser.submit=Riordina pagine
|
pdfOrganiser.submit=Riordina pagine
|
||||||
|
|
||||||
|
|
||||||
#multiTool
|
#multiTool
|
||||||
multiTool.title=Multifunzione PDF
|
multiTool.title=Multifunzione PDF
|
||||||
multiTool.header=Multifunzione PDF
|
multiTool.header=Multifunzione PDF
|
||||||
@@ -298,6 +612,7 @@ pageRemover.header=Rimuovi pagine da un PDF
|
|||||||
pageRemover.pagesToDelete=Pagine da eliminare (inserisci una lista di numeri separati da virgola):
|
pageRemover.pagesToDelete=Pagine da eliminare (inserisci una lista di numeri separati da virgola):
|
||||||
pageRemover.submit=Rimuovi pagine
|
pageRemover.submit=Rimuovi pagine
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=Ruota PDF
|
rotate.title=Ruota PDF
|
||||||
rotate.header=Ruota PDF
|
rotate.header=Ruota PDF
|
||||||
@@ -305,9 +620,7 @@ rotate.selectAngle=Scegli angolo di rotazione (in multipli di 90 gradi):
|
|||||||
rotate.submit=Ruota
|
rotate.submit=Ruota
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
|
||||||
#split
|
|
||||||
split.title=Dividi PDF
|
split.title=Dividi PDF
|
||||||
split.header=Dividi PDF
|
split.header=Dividi PDF
|
||||||
split.desc.1=I numeri che scegli sono le pagine a cui desideri dividere il documento
|
split.desc.1=I numeri che scegli sono le pagine a cui desideri dividere il documento
|
||||||
@@ -322,7 +635,7 @@ split.splitPages=Inserisci pagine a cui dividere:
|
|||||||
split.submit=Dividi
|
split.submit=Dividi
|
||||||
|
|
||||||
|
|
||||||
#imageToPDF
|
#merge
|
||||||
imageToPDF.title=Immagine a PDF
|
imageToPDF.title=Immagine a PDF
|
||||||
imageToPDF.header=Immagine a PDF
|
imageToPDF.header=Immagine a PDF
|
||||||
imageToPDF.submit=Converti
|
imageToPDF.submit=Converti
|
||||||
@@ -332,6 +645,7 @@ imageToPDF.selectText.3=Logica multi-file (funziona solo se ci sono più immagin
|
|||||||
imageToPDF.selectText.4=Unisci in un unico PDF
|
imageToPDF.selectText.4=Unisci in un unico PDF
|
||||||
imageToPDF.selectText.5=Converti in PDF separati
|
imageToPDF.selectText.5=Converti in PDF separati
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDF a immagine
|
pdfToImage.title=PDF a immagine
|
||||||
pdfToImage.header=PDF a immagine
|
pdfToImage.header=PDF a immagine
|
||||||
@@ -345,6 +659,7 @@ pdfToImage.grey=Scala di grigi
|
|||||||
pdfToImage.blackwhite=Bianco e Nero (potresti perdere dettagli!)
|
pdfToImage.blackwhite=Bianco e Nero (potresti perdere dettagli!)
|
||||||
pdfToImage.submit=Converti
|
pdfToImage.submit=Converti
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=Aggiungi Password
|
addPassword.title=Aggiungi Password
|
||||||
addPassword.header=Aggiungi password (crittografa)
|
addPassword.header=Aggiungi password (crittografa)
|
||||||
@@ -366,6 +681,7 @@ addPassword.selectText.15=Restricts what can be done with the document once it i
|
|||||||
addPassword.selectText.16=Restricts the opening of the document itself
|
addPassword.selectText.16=Restricts the opening of the document itself
|
||||||
addPassword.submit=Crittografa
|
addPassword.submit=Crittografa
|
||||||
|
|
||||||
|
|
||||||
#watermark
|
#watermark
|
||||||
watermark.title=Aggiungi Filigrana
|
watermark.title=Aggiungi Filigrana
|
||||||
watermark.header=Aggiungi filigrana
|
watermark.header=Aggiungi filigrana
|
||||||
@@ -376,14 +692,10 @@ watermark.selectText.4=Rotazione (0-360):
|
|||||||
watermark.selectText.5=spazio orizzontale (tra ogni filigrana):
|
watermark.selectText.5=spazio orizzontale (tra ogni filigrana):
|
||||||
watermark.selectText.6=spazio verticale (tra ogni filigrana):
|
watermark.selectText.6=spazio verticale (tra ogni filigrana):
|
||||||
watermark.selectText.7=Opacità (0% - 100%):
|
watermark.selectText.7=Opacità (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=Aggiungi Filigrana
|
watermark.submit=Aggiungi Filigrana
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=Rimuovi Filigrana
|
|
||||||
remove-watermark.header=Rimuovi filigrana
|
|
||||||
remove-watermark.selectText.1=Seleziona PDF da cui rimuovere la filigrana:
|
|
||||||
remove-watermark.selectText.2=Testo:
|
|
||||||
remove-watermark.submit=Rimuovi Filigrana
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=Cambia Permessi
|
permissions.title=Cambia Permessi
|
||||||
@@ -401,6 +713,7 @@ permissions.selectText.9=Previeni stampa
|
|||||||
permissions.selectText.10=Previeni stampa in diversi formati
|
permissions.selectText.10=Previeni stampa in diversi formati
|
||||||
permissions.submit=Cambia Permessi
|
permissions.submit=Cambia Permessi
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=Rimuovi Password
|
removePassword.title=Rimuovi Password
|
||||||
removePassword.header=Rimuovi password (de-crittografa)
|
removePassword.header=Rimuovi password (de-crittografa)
|
||||||
@@ -408,7 +721,9 @@ removePassword.selectText.1=Seleziona PDF da decrittare
|
|||||||
removePassword.selectText.2=Password
|
removePassword.selectText.2=Password
|
||||||
removePassword.submit=Rimuovi Password
|
removePassword.submit=Rimuovi Password
|
||||||
|
|
||||||
changeMetadata.title=Cambia Proprietà
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=Titolo:
|
||||||
changeMetadata.header=Cambia Proprietà
|
changeMetadata.header=Cambia Proprietà
|
||||||
changeMetadata.selectText.1=Imposta i dati che vuoi cambiare
|
changeMetadata.selectText.1=Imposta i dati che vuoi cambiare
|
||||||
changeMetadata.selectText.2=Cancella tutte le proprietà
|
changeMetadata.selectText.2=Cancella tutte le proprietà
|
||||||
@@ -426,27 +741,30 @@ changeMetadata.selectText.4=Altre proprietà:
|
|||||||
changeMetadata.selectText.5=Aggiungi proprietà personalizzata:
|
changeMetadata.selectText.5=Aggiungi proprietà personalizzata:
|
||||||
changeMetadata.submit=Cambia Proprietà
|
changeMetadata.submit=Cambia Proprietà
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=Da Excel a PDF
|
xlsToPdf.title=Da Excel a PDF
|
||||||
xlsToPdf.header=Da Excel a PDF
|
xlsToPdf.header=Da Excel a PDF
|
||||||
xlsToPdf.selectText.1=Seleziona un foglio XLS o XLSX da convertire
|
xlsToPdf.selectText.1=Seleziona un foglio XLS o XLSX da convertire
|
||||||
xlsToPdf.convert=Converti
|
xlsToPdf.convert=Converti
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
|
||||||
pdfToPDFA.title=Da PDF a PDF/A
|
pdfToPDFA.title=Da PDF a PDF/A
|
||||||
pdfToPDFA.header=Da PDF a PDF/A
|
pdfToPDFA.header=Da PDF a PDF/A
|
||||||
pdfToPDFA.credit=Questo servizio utilizza OCRmyPDF per la conversione in PDF/A.
|
pdfToPDFA.credit=Questo servizio utilizza OCRmyPDF per la conversione in PDF/A.
|
||||||
pdfToPDFA.submit=Converti
|
pdfToPDFA.submit=Converti
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=Da PDF a Word
|
PDFToWord.title=Da PDF a Word
|
||||||
PDFToWord.header=Da PDF a Word
|
PDFToWord.header=Da PDF a Word
|
||||||
PDFToWord.selectText.1=Formato file di output
|
PDFToWord.selectText.1=Formato file di output
|
||||||
PDFToWord.credit=Questo servizio utilizza LibreOffice per la conversione.
|
PDFToWord.credit=Questo servizio utilizza LibreOffice per la conversione.
|
||||||
PDFToWord.submit=Converti
|
PDFToWord.submit=Converti
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=Da PDF a presentazione
|
PDFToPresentation.title=Da PDF a presentazione
|
||||||
PDFToPresentation.header=Da PDF a presentazione
|
PDFToPresentation.header=Da PDF a presentazione
|
||||||
PDFToPresentation.selectText.1=Formato file di output
|
PDFToPresentation.selectText.1=Formato file di output
|
||||||
@@ -454,6 +772,7 @@ PDFToPresentation.credit=Questo servizio utilizza LibreOffice per la conversione
|
|||||||
PDFToPresentation.submit=Converti
|
PDFToPresentation.submit=Converti
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
PDFToText.title=Da PDF a testo/RTF
|
PDFToText.title=Da PDF a testo/RTF
|
||||||
PDFToText.header=Da PDF a testo/RTF
|
PDFToText.header=Da PDF a testo/RTF
|
||||||
PDFToText.selectText.1=Formato file di output
|
PDFToText.selectText.1=Formato file di output
|
||||||
@@ -461,11 +780,14 @@ PDFToText.credit=Questo servizio utilizza LibreOffice per la conversione.
|
|||||||
PDFToText.submit=Converti
|
PDFToText.submit=Converti
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=Da PDF a HTML
|
PDFToHTML.title=Da PDF a HTML
|
||||||
PDFToHTML.header=Da PDF a HTML
|
PDFToHTML.header=Da PDF a HTML
|
||||||
PDFToHTML.credit=Questo servizio utilizza LibreOffice per la conversione.
|
PDFToHTML.credit=Questo servizio utilizza LibreOffice per la conversione.
|
||||||
PDFToHTML.submit=Converti
|
PDFToHTML.submit=Converti
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=Da PDF a XML
|
PDFToXML.title=Da PDF a XML
|
||||||
PDFToXML.header=Da PDF a XML
|
PDFToXML.header=Da PDF a XML
|
||||||
PDFToXML.credit=Questo servizio utilizza LibreOffice per la conversione.
|
PDFToXML.credit=Questo servizio utilizza LibreOffice per la conversione.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=PDFを選択
|
pdfPrompt=PDFを選択
|
||||||
@@ -19,141 +19,451 @@ save=保存
|
|||||||
close=閉じる
|
close=閉じる
|
||||||
filesSelected=選択されたファイル
|
filesSelected=選択されたファイル
|
||||||
noFavourites=お気に入りはありません
|
noFavourites=お気に入りはありません
|
||||||
bored=待ち時間が退屈<EFBFBD><EFBFBD>
|
bored=待ち時間が退屈
|
||||||
alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8<EFBFBD>
|
alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8
|
||||||
|
downloadPdf=PDFをダウンロード
|
||||||
|
text=テキスト
|
||||||
|
font=フォント
|
||||||
|
selectFillter=-- 選択 --
|
||||||
|
pageNum=ページ番号
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=PDFにパスワードが設定されてますが、パスワードが入力されてないか間違ってます。
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
|
navbar.convert=変換
|
||||||
|
navbar.security=セキュリティ
|
||||||
|
navbar.other=その他
|
||||||
|
navbar.darkmode=ダークモード
|
||||||
|
navbar.pageOps=ページ操作
|
||||||
|
navbar.settings=設定
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=設定
|
||||||
|
settings.update=利用可能なアップデート
|
||||||
|
settings.appVersion=Appバージョン:
|
||||||
|
settings.downloadOption.title=ダウンロードオプション (zip以外の単一ファイル):
|
||||||
|
settings.downloadOption.1=同じウィンドウで開く
|
||||||
|
settings.downloadOption.2=新しいウィンドウで開く
|
||||||
|
settings.downloadOption.3=ファイルをダウンロード
|
||||||
|
settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
#############
|
#############
|
||||||
home.desc=PDFのあらゆるニーズに対応するローカルホスティングされた総合窓口です。
|
home.desc=PDFのあらゆるニーズに対応するローカルホスティングされた総合窓口です。
|
||||||
|
|
||||||
|
|
||||||
navbar.convert=変換
|
|
||||||
navbar.security=セキュリティ
|
|
||||||
navbar.other=その他
|
|
||||||
navbar.darkmode=ダークモード
|
|
||||||
navbar.pageOps=ページ操作
|
|
||||||
|
|
||||||
home.multiTool.title=PDFマルチツール
|
home.multiTool.title=PDFマルチツール
|
||||||
home.multiTool.desc=ページの結合、回転、並べ替え、削除します。
|
home.multiTool.desc=ページの結合、回転、並べ替え、削除します。
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side,interactive,intractable,move
|
||||||
|
|
||||||
home.merge.title=結合
|
home.merge.title=結合
|
||||||
home.merge.desc=複数のPDFを1つに結合します。
|
home.merge.desc=複数のPDFを1つに結合します。
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
home.split.title=分割
|
home.split.title=分割
|
||||||
home.split.desc=PDFを複数のドキュメントに分割します。
|
home.split.desc=PDFを複数のドキュメントに分割します。
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
home.rotate.title=回転
|
home.rotate.title=回転
|
||||||
home.rotate.desc=PDFを回転します。
|
home.rotate.desc=PDFを回転します。
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=画像をPDFに変換
|
home.imageToPdf.title=画像をPDFに変換
|
||||||
home.imageToPdf.desc=画像 (PNG, JPEG, GIF) をPDFに変換します。
|
home.imageToPdf.desc=画像 (PNG, JPEG, GIF) をPDFに変換します。
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfToImage.title=PDFを画像に変換
|
home.pdfToImage.title=PDFを画像に変換
|
||||||
home.pdfToImage.desc=PDFを画像 (PNG, JPEG, GIF) に変換します。
|
home.pdfToImage.desc=PDFを画像 (PNG, JPEG, GIF) に変換します。
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfOrganiser.title=整理
|
home.pdfOrganiser.title=整理
|
||||||
home.pdfOrganiser.desc=ページの削除/並べ替えします。
|
home.pdfOrganiser.desc=ページの削除/並べ替えします。
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=画像の追加
|
home.addImage.title=画像の追加
|
||||||
home.addImage.desc=PDF上の任意の場所に画像を追加します。
|
home.addImage.desc=PDF上の任意の場所に画像を追加します。
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
home.watermark.title=透かしの追加
|
home.watermark.title=透かしの追加
|
||||||
home.watermark.desc=PDFに独自の透かしを追加します。
|
home.watermark.desc=PDFに独自の透かしを追加します。
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
home.remove-watermark.title=透かしの削除
|
|
||||||
home.remove-watermark.desc=PDFから透かしを削除します。
|
|
||||||
|
|
||||||
home.permissions.title=権限の変更
|
home.permissions.title=権限の変更
|
||||||
home.permissions.desc=PDFの権限を変更します。
|
home.permissions.desc=PDFの権限を変更します。
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=削除
|
home.removePages.title=削除
|
||||||
home.removePages.desc=PDFから不要なページを削除します。
|
home.removePages.desc=PDFから不要なページを削除します。
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
home.addPassword.title=パスワードの追加
|
home.addPassword.title=パスワードの追加
|
||||||
home.addPassword.desc=PDFをパスワードで暗号化します。
|
home.addPassword.desc=PDFをパスワードで暗号化します。
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
home.removePassword.title=パスワードの削除
|
home.removePassword.title=パスワードの削除
|
||||||
home.removePassword.desc=PDFからパスワードの削除します。
|
home.removePassword.desc=PDFからパスワードの削除します。
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
home.compressPdfs.title=圧縮
|
home.compressPdfs.title=圧縮
|
||||||
home.compressPdfs.desc=PDFを圧縮してファイルサイズを小さくします。
|
home.compressPdfs.desc=PDFを圧縮してファイルサイズを小さくします。
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=メタデータの変更
|
home.changeMetadata.title=メタデータの変更
|
||||||
home.changeMetadata.desc=PDFのメタデータを変更/削除/追加します。
|
home.changeMetadata.desc=PDFのメタデータを変更/削除/追加します。
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=ファイルをPDFに変換
|
home.fileToPDF.title=ファイルをPDFに変換
|
||||||
home.fileToPDF.desc=ほぼすべてのファイルをPDFに変換します。 (DOCX, PNG, XLS, PPT, TXTなど)
|
home.fileToPDF.desc=ほぼすべてのファイルをPDFに変換します。 (DOCX, PNG, XLS, PPT, TXTなど)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=OCR / クリーンアップ
|
home.ocr.title=OCR / クリーンアップ
|
||||||
home.ocr.desc=クリーンアップはPDF内の画像からテキストを検出してテキストとして再追加します。
|
home.ocr.desc=クリーンアップはPDF内の画像からテキストを検出してテキストとして再追加します。
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
home.extractImages.title=画像の抽出
|
home.extractImages.title=画像の抽出
|
||||||
home.extractImages.desc=PDFからすべての画像を抽出してzipで保存します。
|
home.extractImages.desc=PDFからすべての画像を抽出してzipで保存します。
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
home.pdfToPDFA.title=PDFをPDF/Aに変換
|
home.pdfToPDFA.title=PDFをPDF/Aに変換
|
||||||
home.pdfToPDFA.desc=長期保存のためにPDFをPDF/Aに変換。
|
home.pdfToPDFA.desc=長期保存のためにPDFをPDF/Aに変換。
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
home.PDFToWord.title=PDFをWordに変換
|
home.PDFToWord.title=PDFをWordに変換
|
||||||
home.PDFToWord.desc=PDFをWord形式に変換します。 (DOC, DOCX および ODT)
|
home.PDFToWord.desc=PDFをWord形式に変換します。 (DOC, DOCX および ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDFをプレゼンテーションに変換
|
home.PDFToPresentation.title=PDFをプレゼンテーションに変換
|
||||||
home.PDFToPresentation.desc=PDFをプレゼンテーション形式に変換します。 (PPT, PPTX および ODP)
|
home.PDFToPresentation.desc=PDFをプレゼンテーション形式に変換します。 (PPT, PPTX および ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=PDFをText/RTFに変換
|
home.PDFToText.title=PDFをText/RTFに変換
|
||||||
home.PDFToText.desc=PDFをTextまたはRTF形式に変換します。
|
home.PDFToText.desc=PDFをTextまたはRTF形式に変換します。
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
home.PDFToHTML.title=PDFをHTMLに変換
|
home.PDFToHTML.title=PDFをHTMLに変換
|
||||||
home.PDFToHTML.desc=PDFをHTML形式に変換します。
|
home.PDFToHTML.desc=PDFをHTML形式に変換します。
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=PDFをXMLに変換
|
home.PDFToXML.title=PDFをXMLに変換
|
||||||
home.PDFToXML.desc=PDFをXML形式に変換します。
|
home.PDFToXML.desc=PDFをXML形式に変換します。
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
home.ScannerImageSplit.title=スキャンされた画像の検出/分割
|
home.ScannerImageSplit.title=スキャンされた画像の検出/分割
|
||||||
home.ScannerImageSplit.desc=1枚の画像/PDFから複数の写真を分割します。
|
home.ScannerImageSplit.desc=1枚の画像/PDFから複数の写真を分割します。
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
home.sign.title=署名
|
home.sign.title=署名
|
||||||
home.sign.desc=手書き、テキストまたは画像によってPDFに署名を追加します。
|
home.sign.desc=手書き、テキストまたは画像によってPDFに署名を追加します。
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
home.flatten.title=平坦化
|
home.flatten.title=平坦化
|
||||||
home.flatten.desc=PDFからインタラクティブな要素とフォームをすべて削除します。
|
home.flatten.desc=PDFからインタラクティブな要素とフォームをすべて削除します。
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
home.repair.title=修復
|
home.repair.title=修復
|
||||||
home.repair.desc=破損したPDFの修復を試みます。
|
home.repair.desc=破損したPDFの修復を試みます。
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
home.removeBlanks.title=空白ページの削除
|
home.removeBlanks.title=空白ページの削除
|
||||||
home.removeBlanks.desc=ドキュメントから空白ページを検出して削除します。
|
home.removeBlanks.desc=ドキュメントから空白ページを検出して削除します。
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
|
|
||||||
home.compare.title=比較
|
home.compare.title=比較
|
||||||
home.compare.desc=2つのPDFを比較して表示します。
|
home.compare.desc=2つのPDFを比較して表示します。
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
home.certSign.title=証明書による署名
|
home.certSign.title=証明書による署名
|
||||||
home.certSign.desc=証明書/キーを使用してPDFに署名します。 (PEM/P12)
|
home.certSign.desc=証明書/キーを使用してPDFに署名します。 (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
home.pageLayout.title=マルチページレイアウト
|
home.pageLayout.title=マルチページレイアウト
|
||||||
home.pageLayout.desc=PDFの複数のページを1ページに結合します。
|
home.pageLayout.desc=PDFの複数のページを1ページに結合します。
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
home.scalePages.title=ページの縮尺の調整
|
home.scalePages.title=ページの縮尺の調整
|
||||||
home.scalePages.desc=ページやコンテンツの縮尺を変更します。
|
home.scalePages.desc=ページやコンテンツの縮尺を変更します。
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
error.pdfPassword=PDFにパスワードが設定されてますが、パスワードが入力されてないか間違ってます。
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
downloadPdf=PDFをダウンロード
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
text=テキスト
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
font=フォント
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
selectFillter=-- 選択 --
|
|
||||||
pageNum=ページ番号
|
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=マルチページレイアウト
|
pageLayout.title=マルチページレイアウト
|
||||||
pageLayout.header=マルチページレイアウト
|
pageLayout.header=マルチページレイアウト
|
||||||
pageLayout.pagesPerSheet=1枚あたりのページ数:
|
pageLayout.pagesPerSheet=1枚あたりのページ数:
|
||||||
pageLayout.submit=送信
|
pageLayout.submit=送信
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=ページの縮尺の調整
|
scalePages.title=ページの縮尺の調整
|
||||||
scalePages.header=ページの縮尺の調整
|
scalePages.header=ページの縮尺の調整
|
||||||
scalePages.pageSize=1ページのサイズ
|
scalePages.pageSize=1ページのサイズ
|
||||||
scalePages.scaleFactor=1ページの拡大レベル (トリミング)。
|
scalePages.scaleFactor=1ページの拡大レベル (トリミング)。
|
||||||
scalePages.submit=送信
|
scalePages.submit=送信
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=証明書による署名
|
certSign.title=証明書による署名
|
||||||
certSign.header=証明書を使用してPDFに署名します。 (進行中)
|
certSign.header=証明書を使用してPDFに署名します。 (進行中)
|
||||||
certSign.selectPDF=署名するPDFファイルを選択:
|
certSign.selectPDF=署名するPDFファイルを選択:
|
||||||
@@ -168,6 +478,8 @@ certSign.location=場所
|
|||||||
certSign.name=名前
|
certSign.name=名前
|
||||||
certSign.submit=PDFに署名
|
certSign.submit=PDFに署名
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=空白の削除
|
removeBlanks.title=空白の削除
|
||||||
removeBlanks.header=空白ページの削除
|
removeBlanks.header=空白ページの削除
|
||||||
removeBlanks.threshold=しきい値 :
|
removeBlanks.threshold=しきい値 :
|
||||||
@@ -176,12 +488,16 @@ removeBlanks.whitePercent=白比率
|
|||||||
removeBlanks.whitePercentDesc=削除するページの白の割合
|
removeBlanks.whitePercentDesc=削除するページの白の割合
|
||||||
removeBlanks.submit=空白ページの削除
|
removeBlanks.submit=空白ページの削除
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=比較
|
compare.title=比較
|
||||||
compare.header=PDFの比較
|
compare.header=PDFの比較
|
||||||
compare.document.1=ドキュメント 1
|
compare.document.1=ドキュメント 1
|
||||||
compare.document.2=ドキュメント 2
|
compare.document.2=ドキュメント 2
|
||||||
compare.submit=比較
|
compare.submit=比較
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=署名
|
sign.title=署名
|
||||||
sign.header=PDFに署名
|
sign.header=PDFに署名
|
||||||
sign.upload=画像をアップロード
|
sign.upload=画像をアップロード
|
||||||
@@ -190,14 +506,20 @@ sign.text=テキスト入力
|
|||||||
sign.clear=クリア
|
sign.clear=クリア
|
||||||
sign.add=追加
|
sign.add=追加
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=修復
|
repair.title=修復
|
||||||
repair.header=PDFを修復
|
repair.header=PDFを修復
|
||||||
repair.submit=修復
|
repair.submit=修復
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=平坦化
|
flatten.title=平坦化
|
||||||
flatten.header=PDFを平坦化する
|
flatten.header=PDFを平坦化する
|
||||||
flatten.submit=平坦化
|
flatten.submit=平坦化
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=角度のしきい値:
|
ScannerImageSplit.selectText.1=角度のしきい値:
|
||||||
ScannerImageSplit.selectText.2=画像を回転させるために必要な絶対角度の最小値を設定 (初期値:10)。
|
ScannerImageSplit.selectText.2=画像を回転させるために必要な絶対角度の最小値を設定 (初期値:10)。
|
||||||
ScannerImageSplit.selectText.3=許容範囲:
|
ScannerImageSplit.selectText.3=許容範囲:
|
||||||
@@ -209,18 +531,6 @@ ScannerImageSplit.selectText.8=画像の最小の輪郭面積のしきい値を
|
|||||||
ScannerImageSplit.selectText.9=境界線サイズ:
|
ScannerImageSplit.selectText.9=境界線サイズ:
|
||||||
ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。
|
ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。
|
||||||
|
|
||||||
navbar.settings=設定
|
|
||||||
settings.title=設定
|
|
||||||
settings.update=利用可能なアップデート
|
|
||||||
settings.appVersion=Appバージョン:
|
|
||||||
settings.downloadOption.title=ダウンロードオプション (zip以外の単一ファイル):
|
|
||||||
settings.downloadOption.1=同じウィンドウで開く
|
|
||||||
settings.downloadOption.2=新しいウィンドウで開く
|
|
||||||
settings.downloadOption.3=ファイルをダウンロード
|
|
||||||
settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / クリーンアップ
|
ocr.title=OCR / クリーンアップ
|
||||||
@@ -242,7 +552,7 @@ ocr.credit=本サービスにはOCRにOCRmyPDFとTesseractを使用していま
|
|||||||
ocr.submit=OCRでPDFを処理する
|
ocr.submit=OCRでPDFを処理する
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=画像の抽出
|
extractImages.title=画像の抽出
|
||||||
extractImages.header=画像の抽出
|
extractImages.header=画像の抽出
|
||||||
extractImages.selectText=抽出した画像のフォーマットを選択
|
extractImages.selectText=抽出した画像のフォーマットを選択
|
||||||
@@ -280,13 +590,17 @@ addImage.submit=画像の追加
|
|||||||
#merge
|
#merge
|
||||||
merge.title=結合
|
merge.title=結合
|
||||||
merge.header=複数のPDFを結合 (2ファイル以上)
|
merge.header=複数のPDFを結合 (2ファイル以上)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=結合
|
merge.submit=結合
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=整理
|
pdfOrganiser.title=整理
|
||||||
pdfOrganiser.header=PDFページの整理
|
pdfOrganiser.header=PDFページの整理
|
||||||
pdfOrganiser.submit=ページの整理
|
pdfOrganiser.submit=ページの整理
|
||||||
|
|
||||||
|
|
||||||
#multiTool
|
#multiTool
|
||||||
multiTool.title=PDFマルチツール
|
multiTool.title=PDFマルチツール
|
||||||
multiTool.header=PDFマルチツール
|
multiTool.header=PDFマルチツール
|
||||||
@@ -298,6 +612,7 @@ pageRemover.header=PDFページ削除
|
|||||||
pageRemover.pagesToDelete=削除するページ (ページ番号のカンマ区切りリストを入力してください):
|
pageRemover.pagesToDelete=削除するページ (ページ番号のカンマ区切りリストを入力してください):
|
||||||
pageRemover.submit=ページ削除
|
pageRemover.submit=ページ削除
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=PDFの回転
|
rotate.title=PDFの回転
|
||||||
rotate.header=PDFの回転
|
rotate.header=PDFの回転
|
||||||
@@ -305,8 +620,6 @@ rotate.selectAngle=回転角度を選択 (90度の倍数):
|
|||||||
rotate.submit=回転
|
rotate.submit=回転
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=PDFの分割
|
split.title=PDFの分割
|
||||||
split.header=PDFの分割
|
split.header=PDFの分割
|
||||||
@@ -332,6 +645,7 @@ imageToPDF.selectText.3=マルチファイルの処理 (複数の画像を操作
|
|||||||
imageToPDF.selectText.4=1つのPDFに結合
|
imageToPDF.selectText.4=1つのPDFに結合
|
||||||
imageToPDF.selectText.5=個別のPDFに変換
|
imageToPDF.selectText.5=個別のPDFに変換
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDFを画像に変換
|
pdfToImage.title=PDFを画像に変換
|
||||||
pdfToImage.header=PDFを画像に変換
|
pdfToImage.header=PDFを画像に変換
|
||||||
@@ -345,6 +659,7 @@ pdfToImage.grey=グレースケール
|
|||||||
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
|
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
|
||||||
pdfToImage.submit=変換
|
pdfToImage.submit=変換
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=パスワードの追加
|
addPassword.title=パスワードの追加
|
||||||
addPassword.header=パスワードの追加 (暗号化)
|
addPassword.header=パスワードの追加 (暗号化)
|
||||||
@@ -366,6 +681,7 @@ addPassword.selectText.15=ドキュメントを開いた後に実行できる操
|
|||||||
addPassword.selectText.16=ドキュメントを開くことを制限します
|
addPassword.selectText.16=ドキュメントを開くことを制限します
|
||||||
addPassword.submit=暗号化
|
addPassword.submit=暗号化
|
||||||
|
|
||||||
|
|
||||||
#watermark
|
#watermark
|
||||||
watermark.title=透かしの追加
|
watermark.title=透かしの追加
|
||||||
watermark.header=透かしの追加
|
watermark.header=透かしの追加
|
||||||
@@ -376,14 +692,10 @@ watermark.selectText.4=回転 (0-360):
|
|||||||
watermark.selectText.5=幅スペース (各透かし間の水平方向のスペース):
|
watermark.selectText.5=幅スペース (各透かし間の水平方向のスペース):
|
||||||
watermark.selectText.6=高さスペース (各透かし間の垂直方向のスペース):
|
watermark.selectText.6=高さスペース (各透かし間の垂直方向のスペース):
|
||||||
watermark.selectText.7=不透明度 (0% - 100%):
|
watermark.selectText.7=不透明度 (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=透かしを追加
|
watermark.submit=透かしを追加
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=透かしの削除
|
|
||||||
remove-watermark.header=透かしの削除
|
|
||||||
remove-watermark.selectText.1=透かしを削除するPDFを選択:
|
|
||||||
remove-watermark.selectText.2=透かしのテキスト:
|
|
||||||
remove-watermark.submit=透かしを削除
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=権限の変更
|
permissions.title=権限の変更
|
||||||
@@ -401,6 +713,7 @@ permissions.selectText.9=印刷を禁止
|
|||||||
permissions.selectText.10=異なる形式の印刷を禁止
|
permissions.selectText.10=異なる形式の印刷を禁止
|
||||||
permissions.submit=変更
|
permissions.submit=変更
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=パスワードの削除
|
removePassword.title=パスワードの削除
|
||||||
removePassword.header=パスワードの削除 (復号化)
|
removePassword.header=パスワードの削除 (復号化)
|
||||||
@@ -408,7 +721,9 @@ removePassword.selectText.1=復号化するPDFを選択
|
|||||||
removePassword.selectText.2=パスワード
|
removePassword.selectText.2=パスワード
|
||||||
removePassword.submit=削除
|
removePassword.submit=削除
|
||||||
|
|
||||||
changeMetadata.title=メタデータの変更
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=タイトル:
|
||||||
changeMetadata.header=メタデータの変更
|
changeMetadata.header=メタデータの変更
|
||||||
changeMetadata.selectText.1=変更したい変数を編集してください
|
changeMetadata.selectText.1=変更したい変数を編集してください
|
||||||
changeMetadata.selectText.2=すべてのメタデータを削除
|
changeMetadata.selectText.2=すべてのメタデータを削除
|
||||||
@@ -426,27 +741,30 @@ changeMetadata.selectText.4=その他のメタデータ:
|
|||||||
changeMetadata.selectText.5=カスタムメタデータの追加
|
changeMetadata.selectText.5=カスタムメタデータの追加
|
||||||
changeMetadata.submit=変更
|
changeMetadata.submit=変更
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=ExcelをPDFに変換
|
xlsToPdf.title=ExcelをPDFに変換
|
||||||
xlsToPdf.header=ExcelをPDFに変換
|
xlsToPdf.header=ExcelをPDFに変換
|
||||||
xlsToPdf.selectText.1=変換するXLSまたはXLSX Execlシートを選択
|
xlsToPdf.selectText.1=変換するXLSまたはXLSX Execlシートを選択
|
||||||
xlsToPdf.convert=変換
|
xlsToPdf.convert=変換
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
|
||||||
pdfToPDFA.title=PDFをPDF/Aに変換
|
pdfToPDFA.title=PDFをPDF/Aに変換
|
||||||
pdfToPDFA.header=PDFをPDF/Aに変換
|
pdfToPDFA.header=PDFをPDF/Aに変換
|
||||||
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。
|
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。
|
||||||
pdfToPDFA.submit=変換
|
pdfToPDFA.submit=変換
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=PDFをWordに変換
|
PDFToWord.title=PDFをWordに変換
|
||||||
PDFToWord.header=PDFをWordに変換
|
PDFToWord.header=PDFをWordに変換
|
||||||
PDFToWord.selectText.1=出力ファイル形式
|
PDFToWord.selectText.1=出力ファイル形式
|
||||||
PDFToWord.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
PDFToWord.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||||
PDFToWord.submit=変換
|
PDFToWord.submit=変換
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDFをプレゼンテーションに変換
|
PDFToPresentation.title=PDFをプレゼンテーションに変換
|
||||||
PDFToPresentation.header=PDFをプレゼンテーションに変換
|
PDFToPresentation.header=PDFをプレゼンテーションに変換
|
||||||
PDFToPresentation.selectText.1=出力ファイル形式
|
PDFToPresentation.selectText.1=出力ファイル形式
|
||||||
@@ -454,6 +772,7 @@ PDFToPresentation.credit=本サービスはファイル変換にLibreOfficeを
|
|||||||
PDFToPresentation.submit=変換
|
PDFToPresentation.submit=変換
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToText
|
||||||
PDFToText.title=PDFをText/RTFに変換
|
PDFToText.title=PDFをText/RTFに変換
|
||||||
PDFToText.header=PDFをText/RTFに変換
|
PDFToText.header=PDFをText/RTFに変換
|
||||||
PDFToText.selectText.1=出力ファイル形式
|
PDFToText.selectText.1=出力ファイル形式
|
||||||
@@ -461,11 +780,14 @@ PDFToText.credit=本サービスはファイル変換にLibreOfficeを使用し
|
|||||||
PDFToText.submit=変換
|
PDFToText.submit=変換
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDFをHTMLに変換
|
PDFToHTML.title=PDFをHTMLに変換
|
||||||
PDFToHTML.header=PDFをHTMLに変換
|
PDFToHTML.header=PDFをHTMLに変換
|
||||||
PDFToHTML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
PDFToHTML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||||
PDFToHTML.submit=変換
|
PDFToHTML.submit=変換
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=PDFをXMLに変換
|
PDFToXML.title=PDFをXMLに変換
|
||||||
PDFToXML.header=PDFをXMLに変換
|
PDFToXML.header=PDFをXMLに変換
|
||||||
PDFToXML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
PDFToXML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=PDF 선택
|
pdfPrompt=PDF 선택
|
||||||
@@ -21,139 +21,449 @@ filesSelected=개 파일 선택됨
|
|||||||
noFavourites=즐겨찾기 없음
|
noFavourites=즐겨찾기 없음
|
||||||
bored=기다리는 게 지루하신가요?
|
bored=기다리는 게 지루하신가요?
|
||||||
alphabet=\uC54C\uD30C\uBCB3
|
alphabet=\uC54C\uD30C\uBCB3
|
||||||
|
downloadPdf=PDF 다운로드
|
||||||
|
text=텍스트
|
||||||
|
font=폰트
|
||||||
|
selectFillter=-- 선택 --
|
||||||
|
pageNum=페이지 번호
|
||||||
|
sizes.small=Small
|
||||||
|
sizes.medium=Medium
|
||||||
|
sizes.large=Large
|
||||||
|
sizes.x-large=X-Large
|
||||||
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
delete=Delete
|
||||||
|
username=Username
|
||||||
|
password=Password
|
||||||
|
welcome=Welcome
|
||||||
|
=Property
|
||||||
|
|
||||||
|
#############
|
||||||
|
# NAVBAR #
|
||||||
|
#############
|
||||||
|
navbar.convert=변환
|
||||||
|
navbar.security=보안
|
||||||
|
navbar.other=기타
|
||||||
|
navbar.darkmode=다크 모드
|
||||||
|
navbar.pageOps=Page Operations
|
||||||
|
navbar.settings=설정
|
||||||
|
|
||||||
|
#############
|
||||||
|
# SETTINGS #
|
||||||
|
#############
|
||||||
|
settings.title=설정
|
||||||
|
settings.update=업데이트 가능
|
||||||
|
settings.appVersion=앱 버전:
|
||||||
|
settings.downloadOption.title=다운로드 옵션 선택 (zip 파일이 아닌 단일 파일 다운로드 시):
|
||||||
|
settings.downloadOption.1=현재 창에서 열기
|
||||||
|
settings.downloadOption.2=새 창에서 열기
|
||||||
|
settings.downloadOption.3=다운로드
|
||||||
|
settings.zipThreshold=다운로드한 파일 수가 초과된 경우 파일 압축하기
|
||||||
|
settings.signOut=Sign Out
|
||||||
|
settings.accountSettings=Account Settings
|
||||||
|
|
||||||
|
account.title=Account Settings
|
||||||
|
account.accountSettings=Account Settings
|
||||||
|
account.adminSettings=Admin Settings - View and Add Users
|
||||||
|
account.userControlSettings=User Control Settings
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.changeUsername=Change Username
|
||||||
|
account.password=Confirmation Password
|
||||||
|
account.oldPassword=Old password
|
||||||
|
account.newPassword=New Password
|
||||||
|
account.changePassword=Change Password
|
||||||
|
account.confirmNewPassword=Confirm New Password
|
||||||
|
account.signOut=Sign Out
|
||||||
|
account.yourApiKey=Your API Key
|
||||||
|
account.syncTitle=Sync browser settings with Account
|
||||||
|
account.settingsCompare=Settings Comparison:
|
||||||
|
account.property=Property
|
||||||
|
account.webBrowserSettings=Web Browser Setting
|
||||||
|
account.syncToBrowser=Sync Account -> Browser
|
||||||
|
account.syncToAccount=Sync Account <- Browser
|
||||||
|
|
||||||
|
|
||||||
|
adminUserSettings.title=User Control Settings
|
||||||
|
adminUserSettings.header=Admin User Control Settings
|
||||||
|
adminUserSettings.admin=Admin
|
||||||
|
adminUserSettings.user=User
|
||||||
|
adminUserSettings.addUser=Add New User
|
||||||
|
adminUserSettings.roles=Roles
|
||||||
|
adminUserSettings.role=Role
|
||||||
|
adminUserSettings.actions=Actions
|
||||||
|
adminUserSettings.apiUser=Limited API User
|
||||||
|
adminUserSettings.webOnlyUser=Web Only User
|
||||||
|
adminUserSettings.submit=Save User
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
#############
|
#############
|
||||||
home.desc=당신의 PDF에 필요한 모든 것이 있는 로컬 호스팅된 원스톱 숍입니다.
|
home.desc=당신의 PDF에 필요한 모든 것이 있는 로컬 호스팅된 원스톱 숍입니다.
|
||||||
|
|
||||||
|
|
||||||
navbar.convert=변환
|
|
||||||
navbar.security=보안
|
|
||||||
navbar.other=기타
|
|
||||||
navbar.darkmode=다크 모드
|
|
||||||
navbar.pageOps=Page Operations
|
|
||||||
|
|
||||||
home.multiTool.title=PDF 멀티 툴
|
home.multiTool.title=PDF 멀티 툴
|
||||||
home.multiTool.desc=페이지를 병합, 회전, 재배열, 제거하세요.
|
home.multiTool.desc=페이지를 병합, 회전, 재배열, 제거하세요.
|
||||||
|
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side
|
||||||
|
|
||||||
home.merge.title=병합
|
home.merge.title=병합
|
||||||
home.merge.desc=여러 개의 PDF를 쉽게 하나로 합치세요.
|
home.merge.desc=여러 개의 PDF를 쉽게 하나로 합치세요.
|
||||||
|
merge.tags=merge,Page operations,Back end,server side
|
||||||
|
|
||||||
home.split.title=분할
|
home.split.title=분할
|
||||||
home.split.desc=PDF를 여러 개의 문서로 분할하세요.
|
home.split.desc=PDF를 여러 개의 문서로 분할하세요.
|
||||||
|
split.tags=Page operations,divide,Multi Page,cut,server side
|
||||||
|
|
||||||
home.rotate.title=회전
|
home.rotate.title=회전
|
||||||
home.rotate.desc=PDF를 쉽게 회전하세요.
|
home.rotate.desc=PDF를 쉽게 회전하세요.
|
||||||
|
rotate.tags=server side
|
||||||
|
|
||||||
|
|
||||||
home.imageToPdf.title=Image to PDF
|
home.imageToPdf.title=Image to PDF
|
||||||
home.imageToPdf.desc=이미지(PNG, JPEG, GIF)를 PDF로 변환하세요.
|
home.imageToPdf.desc=이미지(PNG, JPEG, GIF)를 PDF로 변환하세요.
|
||||||
|
imageToPdf.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfToImage.title=PDF to Image
|
home.pdfToImage.title=PDF to Image
|
||||||
home.pdfToImage.desc=PDF를 이미지(PNG, JPEG, GIF)로 변환하세요.
|
home.pdfToImage.desc=PDF를 이미지(PNG, JPEG, GIF)로 변환하세요.
|
||||||
|
pdfToImage.tags=conversion,img,jpg,picture,photo
|
||||||
|
|
||||||
home.pdfOrganiser.title=정렬
|
home.pdfOrganiser.title=정렬
|
||||||
home.pdfOrganiser.desc=페이지를 원하는 순서대로 제거/재배열하세요.
|
home.pdfOrganiser.desc=페이지를 원하는 순서대로 제거/재배열하세요.
|
||||||
|
pdfOrganiser.tags=duplex,even,odd,sort,move
|
||||||
|
|
||||||
|
|
||||||
home.addImage.title=사진 추가
|
home.addImage.title=사진 추가
|
||||||
home.addImage.desc=PDF의 설정된 위치에 이미지를 추가하세요.(개발 중)
|
home.addImage.desc=PDF의 설정된 위치에 이미지를 추가하세요.(개발 중)
|
||||||
|
addImage.tags=img,jpg,picture,photo
|
||||||
|
|
||||||
home.watermark.title=워터마크 추가
|
home.watermark.title=워터마크 추가
|
||||||
home.watermark.desc=PDF 문서에 사용자 지정 워터마크를 추가하세요.
|
home.watermark.desc=PDF 문서에 사용자 지정 워터마크를 추가하세요.
|
||||||
|
watermark.tags=Text,repeating,label,own,copyright,trademark,img,jpg,picture,photo
|
||||||
home.remove-watermark.title=워터마크 제거
|
|
||||||
home.remove-watermark.desc=PDF 문서에서 워터마크를 제거하세요.
|
|
||||||
|
|
||||||
home.permissions.title=권한 변경
|
home.permissions.title=권한 변경
|
||||||
home.permissions.desc=PDF 문서의 권한을 변경하세요.
|
home.permissions.desc=PDF 문서의 권한을 변경하세요.
|
||||||
|
permissions.tags=read,write,edit,print
|
||||||
|
|
||||||
|
|
||||||
home.removePages.title=제거
|
home.removePages.title=제거
|
||||||
home.removePages.desc=PDF 문서에서 원치 않는 페이지를 제거하세요.
|
home.removePages.desc=PDF 문서에서 원치 않는 페이지를 제거하세요.
|
||||||
|
removePages.tags=Remove pages,delete pages
|
||||||
|
|
||||||
home.addPassword.title=비밀번호 추가
|
home.addPassword.title=비밀번호 추가
|
||||||
home.addPassword.desc=PDF 문서를 비밀번호로 암호화하세요.
|
home.addPassword.desc=PDF 문서를 비밀번호로 암호화하세요.
|
||||||
|
addPassword.tags=secure,security
|
||||||
|
|
||||||
home.removePassword.title=비밀번호 제거
|
home.removePassword.title=비밀번호 제거
|
||||||
home.removePassword.desc=PDF 문서에서 비밀번호를 제거하세요.
|
home.removePassword.desc=PDF 문서에서 비밀번호를 제거하세요.
|
||||||
|
removePassword.tags=secure,Decrypt,security,unpassword,delete password
|
||||||
|
|
||||||
home.compressPdfs.title=압축
|
home.compressPdfs.title=압축
|
||||||
home.compressPdfs.desc=파일 크기를 줄이기 위해 PDF 문서를 압축하세요.
|
home.compressPdfs.desc=파일 크기를 줄이기 위해 PDF 문서를 압축하세요.
|
||||||
|
compressPdfs.tags=squish,small,tiny
|
||||||
|
|
||||||
|
|
||||||
home.changeMetadata.title=메타데이터 변경
|
home.changeMetadata.title=메타데이터 변경
|
||||||
home.changeMetadata.desc=PDF 문서의 메타데이터를 수정/제거/추가하세요.
|
home.changeMetadata.desc=PDF 문서의 메타데이터를 수정/제거/추가하세요.
|
||||||
|
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=파일을 PDF로 변환
|
home.fileToPDF.title=파일을 PDF로 변환
|
||||||
home.fileToPDF.desc=거의 모든 파일을 PDF로 변환하세요(DOCX, PNG, XLS, PPT, TXT 등)
|
home.fileToPDF.desc=거의 모든 파일을 PDF로 변환하세요(DOCX, PNG, XLS, PPT, TXT 등)
|
||||||
|
fileToPDF.tags=transformation,format,document,picture,slide,text,conversion,office,docs,word,excel,powerpoint
|
||||||
|
|
||||||
home.ocr.title=OCR / 깔끔하게 스캔
|
home.ocr.title=OCR / 깔끔하게 스캔
|
||||||
home.ocr.desc=깔끔하게 스캔하고 PDF 내의 이미지에서 텍스트를 감지하여 텍스트로 다시 추가합니다.
|
home.ocr.desc=깔끔하게 스캔하고 PDF 내의 이미지에서 텍스트를 감지하여 텍스트로 다시 추가합니다.
|
||||||
|
ocr.tags=recognition,text,image,scan,read,identify,detection,editable
|
||||||
|
|
||||||
|
|
||||||
home.extractImages.title=이미지 추출
|
home.extractImages.title=이미지 추출
|
||||||
home.extractImages.desc=PDF에서 모든 이미지를 추출하여 zip으로 저장합니다.
|
home.extractImages.desc=PDF에서 모든 이미지를 추출하여 zip으로 저장합니다.
|
||||||
|
extractImages.tags=picture,photo,save,archive,zip,capture,grab
|
||||||
|
|
||||||
home.pdfToPDFA.title=PDF to PDF/A
|
home.pdfToPDFA.title=PDF to PDF/A
|
||||||
home.pdfToPDFA.desc=장기 보관을 위해 PDF를 PDF/A 문서로 변환하세요.
|
home.pdfToPDFA.desc=장기 보관을 위해 PDF를 PDF/A 문서로 변환하세요.
|
||||||
|
pdfToPDFA.tags=archive,long-term,standard,conversion,storage,preservation
|
||||||
|
|
||||||
home.PDFToWord.title=PDF to Word
|
home.PDFToWord.title=PDF to Word
|
||||||
home.PDFToWord.desc=PDF를 Word 형식으로 변환하세요. (DOC, DOCX, ODT)
|
home.PDFToWord.desc=PDF를 Word 형식으로 변환하세요. (DOC, DOCX, ODT)
|
||||||
|
PDFToWord.tags=doc,docx,odt,word,transformation,format,conversion,office,microsoft,docfile
|
||||||
|
|
||||||
home.PDFToPresentation.title=PDF to 프리젠테이션
|
home.PDFToPresentation.title=PDF to 프리젠테이션
|
||||||
home.PDFToPresentation.desc=PDF를 프리젠테이션 형식으로 변환하세요. (PPT, PPTX, ODP)
|
home.PDFToPresentation.desc=PDF를 프리젠테이션 형식으로 변환하세요. (PPT, PPTX, ODP)
|
||||||
|
PDFToPresentation.tags=slides,show,office,microsoft
|
||||||
|
|
||||||
home.PDFToText.title=PDF to 텍스트/RTF
|
home.PDFToText.title=PDF to 텍스트/RTF
|
||||||
home.PDFToText.desc=PDF를 텍스트 또는 RTF 형식으로 변환하세요.
|
home.PDFToText.desc=PDF를 텍스트 또는 RTF 형식으로 변환하세요.
|
||||||
|
PDFToText.tags=richformat,richtextformat,rich text format
|
||||||
|
|
||||||
home.PDFToHTML.title=PDF to HTML
|
home.PDFToHTML.title=PDF to HTML
|
||||||
home.PDFToHTML.desc=PDF를 HTML 형식으로 변환하세요.
|
home.PDFToHTML.desc=PDF를 HTML 형식으로 변환하세요.
|
||||||
|
PDFToHTML.tags=web content,browser friendly
|
||||||
|
|
||||||
|
|
||||||
home.PDFToXML.title=PDF to XML
|
home.PDFToXML.title=PDF to XML
|
||||||
home.PDFToXML.desc=PDF를 XML 형식으로 변환하세요.
|
home.PDFToXML.desc=PDF를 XML 형식으로 변환하세요.
|
||||||
|
PDFToXML.tags=data-extraction,structured-content,interop,transformation,convert
|
||||||
|
|
||||||
home.ScannerImageSplit.title=스캔한 사진 감지/분할
|
home.ScannerImageSplit.title=스캔한 사진 감지/분할
|
||||||
home.ScannerImageSplit.desc=사진/PDF 내에서 여러 장의 사진을 분할합니다.
|
home.ScannerImageSplit.desc=사진/PDF 내에서 여러 장의 사진을 분할합니다.
|
||||||
|
ScannerImageSplit.tags=separate,auto-detect,scans,multi-photo,organize
|
||||||
|
|
||||||
home.sign.title=서명
|
home.sign.title=서명
|
||||||
home.sign.desc=PDF에 그림, 텍스트, 이미지로 서명을 추가합니다.
|
home.sign.desc=PDF에 그림, 텍스트, 이미지로 서명을 추가합니다.
|
||||||
|
sign.tags=authorize,initials,drawn-signature,text-sign,image-signature
|
||||||
|
|
||||||
home.flatten.title=합치기
|
home.flatten.title=합치기
|
||||||
home.flatten.desc=PDF에서 모든 인터랙션 요소와 양식을 제거하세요.
|
home.flatten.desc=PDF에서 모든 인터랙션 요소와 양식을 제거하세요.
|
||||||
|
flatten.tags=static,deactivate,non-interactive,streamline
|
||||||
|
|
||||||
home.repair.title=복구
|
home.repair.title=복구
|
||||||
home.repair.desc=손상된 PDF의 복구를 시도합니다.
|
home.repair.desc=손상된 PDF의 복구를 시도합니다.
|
||||||
|
repair.tags=fix,restore,correction,recover
|
||||||
|
|
||||||
home.removeBlanks.title=빈 페이지 제거
|
home.removeBlanks.title=빈 페이지 제거
|
||||||
home.removeBlanks.desc=문서에서 빈 페이지를 감지하고 제거합니다.
|
home.removeBlanks.desc=문서에서 빈 페이지를 감지하고 제거합니다.
|
||||||
|
removeBlanks.tags=cleanup,streamline,non-content,organize
|
||||||
|
|
||||||
home.compare.title=비교
|
home.compare.title=비교
|
||||||
home.compare.desc=2개의 PDF 문서를 비교하고 차이를 표시합니다.
|
home.compare.desc=2개의 PDF 문서를 비교하고 차이를 표시합니다.
|
||||||
|
compare.tags=differentiate,contrast,changes,analysis
|
||||||
|
|
||||||
home.certSign.title=인증서로 서명
|
home.certSign.title=인증서로 서명
|
||||||
home.certSign.desc=PDF에 인증서/키로 서명합니다. (PEM/P12)
|
home.certSign.desc=PDF에 인증서/키로 서명합니다. (PEM/P12)
|
||||||
|
certSign.tags=authenticate,PEM,P12,official,encrypt
|
||||||
|
|
||||||
home.pageLayout.title=Multi-Page Layout
|
home.pageLayout.title=Multi-Page Layout
|
||||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||||
|
pageLayout.tags=merge,composite,single-view,organize
|
||||||
|
|
||||||
home.scalePages.title=Adjust page size/scale
|
home.scalePages.title=Adjust page size/scale
|
||||||
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
||||||
|
scalePages.tags=resize,modify,dimension,adapt
|
||||||
|
|
||||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
home.pipeline.title=Pipeline (Advanced)
|
||||||
|
home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts
|
||||||
|
pipeline.tags=automate,sequence,scripted,batch-process
|
||||||
|
|
||||||
downloadPdf=PDF 다운로드
|
home.add-page-numbers.title=Add Page Numbers
|
||||||
text=텍스트
|
home.add-page-numbers.desc=Add Page numbers throughout a document in a set location
|
||||||
font=폰트
|
add-page-numbers.tags=paginate,label,organize,index
|
||||||
selectFillter=-- 선택 --
|
|
||||||
pageNum=페이지 번호
|
|
||||||
|
|
||||||
|
home.auto-rename.title=Auto Rename PDF File
|
||||||
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
|
home.adjust-contrast.title=Adjust Colors/Contrast
|
||||||
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
|
adjust-contrast.tags=color-correction,tune,modify,enhance
|
||||||
|
|
||||||
|
home.crop.title=Crop PDF
|
||||||
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
|
crop.tags=trim,shrink,edit,shape
|
||||||
|
|
||||||
|
home.autoSplitPDF.title=Auto Split Pages
|
||||||
|
home.autoSplitPDF.desc=Auto Split Scanned PDF with physical scanned page splitter QR Code
|
||||||
|
autoSplitPDF.tags=QR-based,separate,scan-segment,organize
|
||||||
|
|
||||||
|
home.sanitizePdf.title=Sanitize
|
||||||
|
home.sanitizePdf.desc=Remove scripts and other elements from PDF files
|
||||||
|
sanitizePdf.tags=clean,secure,safe,remove-threats
|
||||||
|
|
||||||
|
home.URLToPDF.title=URL/Website To PDF
|
||||||
|
home.URLToPDF.desc=Converts any http(s)URL to PDF
|
||||||
|
URLToPDF.tags=web-capture,save-page,web-to-doc,archive
|
||||||
|
|
||||||
|
home.HTMLToPDF.title=HTML to PDF
|
||||||
|
home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||||
|
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.MarkdownToPDF.title=Markdown to PDF
|
||||||
|
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||||
|
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||||
|
|
||||||
|
|
||||||
|
home.getPdfInfo.title=Get ALL Info on PDF
|
||||||
|
home.getPdfInfo.desc=Grabs any and all information possible on PDFs
|
||||||
|
getPdfInfo.tags=infomation,data,stats,statistics
|
||||||
|
|
||||||
|
|
||||||
|
home.extractPage.title=Extract page(s)
|
||||||
|
home.extractPage.desc=Extracts select pages from PDF
|
||||||
|
extractPage.tags=extract
|
||||||
|
|
||||||
|
|
||||||
|
home.PdfToSinglePage.title=PDF to Single Large Page
|
||||||
|
home.PdfToSinglePage.desc=Merges all PDF pages into one large single page
|
||||||
|
PdfToSinglePage.tags=single page
|
||||||
|
|
||||||
|
|
||||||
|
home.showJS.title=Show Javascript
|
||||||
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=JS
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# #
|
||||||
|
# WEB PAGES #
|
||||||
|
# #
|
||||||
|
###########################
|
||||||
|
#login
|
||||||
|
##########################
|
||||||
|
### TODO: Translate ###
|
||||||
|
##########################
|
||||||
|
login.title=Sign in
|
||||||
|
login.signin=Sign in
|
||||||
|
login.rememberme=Remember me
|
||||||
|
login.invalid=Invalid username or password.
|
||||||
|
login.locked=Your account has been locked.
|
||||||
|
login.signinTitle=Please sign in
|
||||||
|
|
||||||
|
|
||||||
|
#auto-redact
|
||||||
|
autoRedact.title=Auto Redact
|
||||||
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#showJS
|
||||||
|
showJS.title=Show Javascript
|
||||||
|
showJS.header=Show Javascript
|
||||||
|
showJS.downloadJS=Download Javascript
|
||||||
|
showJS.submit=Show
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToSinglePage
|
||||||
|
pdfToSinglePage.title=PDF To Single Page
|
||||||
|
pdfToSinglePage.header=PDF To Single Page
|
||||||
|
pdfToSinglePage.submit=Convert To Single Page
|
||||||
|
|
||||||
|
|
||||||
|
#pageExtracter
|
||||||
|
pageExtracter.title=Extract Pages
|
||||||
|
pageExtracter.header=Extract Pages
|
||||||
|
pageExtracter.submit=Extract
|
||||||
|
|
||||||
|
|
||||||
|
#getPdfInfo
|
||||||
|
getPdfInfo.title=Get Info on PDF
|
||||||
|
getPdfInfo.header=Get Info on PDF
|
||||||
|
getPdfInfo.submit=Get Info
|
||||||
|
getPdfInfo.downloadJson=Download JSON
|
||||||
|
|
||||||
|
|
||||||
|
#markdown-to-pdf
|
||||||
|
MarkdownToPDF.title=Markdown To PDF
|
||||||
|
MarkdownToPDF.header=Markdown To PDF
|
||||||
|
MarkdownToPDF.submit=Convert
|
||||||
|
MarkdownToPDF.help=Work in progress
|
||||||
|
MarkdownToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#url-to-pdf
|
||||||
|
URLToPDF.title=URL To PDF
|
||||||
|
URLToPDF.header=URL To PDF
|
||||||
|
URLToPDF.submit=Convert
|
||||||
|
URLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#html-to-pdf
|
||||||
|
HTMLToPDF.title=HTML To PDF
|
||||||
|
HTMLToPDF.header=HTML To PDF
|
||||||
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
|
HTMLToPDF.submit=Convert
|
||||||
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
|
#sanitizePDF
|
||||||
|
sanitizePDF.title=Sanitize PDF
|
||||||
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
sanitizePDF.selectText.1=Remove JavaScript actions
|
||||||
|
sanitizePDF.selectText.2=Remove embedded files
|
||||||
|
sanitizePDF.selectText.3=Remove metadata
|
||||||
|
sanitizePDF.selectText.4=Remove links
|
||||||
|
sanitizePDF.selectText.5=Remove fonts
|
||||||
|
sanitizePDF.submit=Sanitize PDF
|
||||||
|
|
||||||
|
|
||||||
|
#addPageNumbers
|
||||||
|
addPageNumbers.title=Add Page Numbers
|
||||||
|
addPageNumbers.header=Add Page Numbers
|
||||||
|
addPageNumbers.selectText.1=Select PDF file:
|
||||||
|
addPageNumbers.selectText.2=Margin Size
|
||||||
|
addPageNumbers.selectText.3=Position
|
||||||
|
addPageNumbers.selectText.4=Starting Number
|
||||||
|
addPageNumbers.selectText.5=Pages to Number
|
||||||
|
addPageNumbers.selectText.6=Custom Text
|
||||||
|
addPageNumbers.customTextDesc=Custom Text
|
||||||
|
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||||
|
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||||
|
addPageNumbers.submit=Add Page Numbers
|
||||||
|
|
||||||
|
|
||||||
|
#auto-rename
|
||||||
|
auto-rename.title=Auto Rename
|
||||||
|
auto-rename.header=Auto Rename PDF
|
||||||
|
auto-rename.submit=Auto Rename
|
||||||
|
|
||||||
|
|
||||||
|
#adjustContrast
|
||||||
|
adjustContrast.title=Adjust Contrast
|
||||||
|
adjustContrast.header=Adjust Contrast
|
||||||
|
adjustContrast.contrast=Contrast:
|
||||||
|
adjustContrast.brightness=Brightness:
|
||||||
|
adjustContrast.saturation=Saturation:
|
||||||
|
adjustContrast.download=Download
|
||||||
|
|
||||||
|
|
||||||
|
#crop
|
||||||
|
crop.title=Crop
|
||||||
|
crop.header=Crop Image
|
||||||
|
crop.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#autoSplitPDF
|
||||||
|
autoSplitPDF.title=Auto Split PDF
|
||||||
|
autoSplitPDF.header=Auto Split PDF
|
||||||
|
autoSplitPDF.description=Print, Insert, Scan, upload, and let us auto-separate your documents. No manual work sorting needed.
|
||||||
|
autoSplitPDF.selectText.1=Print out some divider sheets from below (Black and white is fine).
|
||||||
|
autoSplitPDF.selectText.2=Scan all your documents at once by inserting the divider sheet between them.
|
||||||
|
autoSplitPDF.selectText.3=Upload the single large scanned PDF file and let Stirling PDF handle the rest.
|
||||||
|
autoSplitPDF.selectText.4=Divider pages are automatically detected and removed, guaranteeing a neat final document.
|
||||||
|
autoSplitPDF.formPrompt=Submit PDF containing Stirling-PDF Page dividers:
|
||||||
|
autoSplitPDF.duplexMode=Duplex Mode (Front and back scanning)
|
||||||
|
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||||
|
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||||
|
autoSplitPDF.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#pipeline
|
||||||
|
pipeline.title=Pipeline
|
||||||
|
|
||||||
|
|
||||||
|
#pageLayout
|
||||||
pageLayout.title=Multi Page Layout
|
pageLayout.title=Multi Page Layout
|
||||||
pageLayout.header=Multi Page Layout
|
pageLayout.header=Multi Page Layout
|
||||||
pageLayout.pagesPerSheet=Pages per sheet:
|
pageLayout.pagesPerSheet=Pages per sheet:
|
||||||
pageLayout.submit=Submit
|
pageLayout.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#scalePages
|
||||||
scalePages.title=Adjust page-scale
|
scalePages.title=Adjust page-scale
|
||||||
scalePages.header=Adjust page-scale
|
scalePages.header=Adjust page-scale
|
||||||
scalePages.pageSize=Size of a page of the document.
|
scalePages.pageSize=Size of a page of the document.
|
||||||
scalePages.scaleFactor=Zoom level (crop) of a page.
|
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||||
scalePages.submit=Submit
|
scalePages.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
|
#certSign
|
||||||
certSign.title=인증서로 서명
|
certSign.title=인증서로 서명
|
||||||
certSign.header=PDF에 당신의 인증서로 서명하세요 (개발 중)
|
certSign.header=PDF에 당신의 인증서로 서명하세요 (개발 중)
|
||||||
certSign.selectPDF=서명할 PDF를 선택하세요:
|
certSign.selectPDF=서명할 PDF를 선택하세요:
|
||||||
@@ -166,11 +476,10 @@ certSign.showSig=서명 보기
|
|||||||
certSign.reason=이유
|
certSign.reason=이유
|
||||||
certSign.location=위치
|
certSign.location=위치
|
||||||
certSign.name=이름
|
certSign.name=이름
|
||||||
|
|
||||||
certSign.submit=PDF 서명
|
certSign.submit=PDF 서명
|
||||||
|
|
||||||
|
|
||||||
|
#removeBlanks
|
||||||
removeBlanks.title=빈 페이지 제거
|
removeBlanks.title=빈 페이지 제거
|
||||||
removeBlanks.header=빈 페이지 제거
|
removeBlanks.header=빈 페이지 제거
|
||||||
removeBlanks.threshold=임계값:
|
removeBlanks.threshold=임계값:
|
||||||
@@ -179,12 +488,16 @@ removeBlanks.whitePercent=흰색 비율 (%):
|
|||||||
removeBlanks.whitePercentDesc=제거될 페이지의 흰색 픽셀 비율
|
removeBlanks.whitePercentDesc=제거될 페이지의 흰색 픽셀 비율
|
||||||
removeBlanks.submit=빈 페이지 제거
|
removeBlanks.submit=빈 페이지 제거
|
||||||
|
|
||||||
|
|
||||||
|
#compare
|
||||||
compare.title=비교
|
compare.title=비교
|
||||||
compare.header=PDF 비교
|
compare.header=PDF 비교
|
||||||
compare.document.1=문서 1
|
compare.document.1=문서 1
|
||||||
compare.document.2=문서 2
|
compare.document.2=문서 2
|
||||||
compare.submit=비교
|
compare.submit=비교
|
||||||
|
|
||||||
|
|
||||||
|
#sign
|
||||||
sign.title=서명
|
sign.title=서명
|
||||||
sign.header=PDF에 서명
|
sign.header=PDF에 서명
|
||||||
sign.upload=이미지 업로드
|
sign.upload=이미지 업로드
|
||||||
@@ -193,14 +506,20 @@ sign.text=텍스트 입력
|
|||||||
sign.clear=초기화
|
sign.clear=초기화
|
||||||
sign.add=추가
|
sign.add=추가
|
||||||
|
|
||||||
|
|
||||||
|
#repair
|
||||||
repair.title=복구
|
repair.title=복구
|
||||||
repair.header=PDF 복구
|
repair.header=PDF 복구
|
||||||
repair.submit=복구
|
repair.submit=복구
|
||||||
|
|
||||||
|
|
||||||
|
#flatten
|
||||||
flatten.title=합치기
|
flatten.title=합치기
|
||||||
flatten.header=PDF 합치기
|
flatten.header=PDF 합치기
|
||||||
flatten.submit=합치기
|
flatten.submit=합치기
|
||||||
|
|
||||||
|
|
||||||
|
#ScannerImageSplit
|
||||||
ScannerImageSplit.selectText.1=각도 임계값:
|
ScannerImageSplit.selectText.1=각도 임계값:
|
||||||
ScannerImageSplit.selectText.2=이미지를 회전하는 데 필요한 최소 절대 각도를 설정합니다(기본값: 10).
|
ScannerImageSplit.selectText.2=이미지를 회전하는 데 필요한 최소 절대 각도를 설정합니다(기본값: 10).
|
||||||
ScannerImageSplit.selectText.3=오차 범위:
|
ScannerImageSplit.selectText.3=오차 범위:
|
||||||
@@ -212,19 +531,6 @@ ScannerImageSplit.selectText.8=사진의 최소 윤곽선 영역 임계값을
|
|||||||
ScannerImageSplit.selectText.9=테두리 크기:
|
ScannerImageSplit.selectText.9=테두리 크기:
|
||||||
ScannerImageSplit.selectText.10=출력에서 흰색 테두리를 방지하기 위해 추가 및 제거되는 테두리의 크기를 설정합니다(기본값: 1).
|
ScannerImageSplit.selectText.10=출력에서 흰색 테두리를 방지하기 위해 추가 및 제거되는 테두리의 크기를 설정합니다(기본값: 1).
|
||||||
|
|
||||||
navbar.settings=설정
|
|
||||||
settings.title=설정
|
|
||||||
settings.update=업데이트 가능
|
|
||||||
settings.appVersion=앱 버전:
|
|
||||||
settings.downloadOption.title=다운로드 옵션 선택 (zip 파일이 아닌 단일 파일 다운로드 시):
|
|
||||||
settings.downloadOption.1=현재 창에서 열기
|
|
||||||
settings.downloadOption.2=새 창에서 열기
|
|
||||||
settings.downloadOption.3=다운로드
|
|
||||||
settings.zipThreshold=다운로드한 파일 수가 초과된 경우 파일 압축하기
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR / 깔끔하게 스캔
|
ocr.title=OCR / 깔끔하게 스캔
|
||||||
@@ -246,7 +552,7 @@ ocr.credit=이 서비스는 OCR에 OCRmyPDF와 Tesseract를 사용합니다.
|
|||||||
ocr.submit=OCR로 PDF 처리
|
ocr.submit=OCR로 PDF 처리
|
||||||
|
|
||||||
|
|
||||||
|
#extractImages
|
||||||
extractImages.title=이미지 추출
|
extractImages.title=이미지 추출
|
||||||
extractImages.header=이미지 추출
|
extractImages.header=이미지 추출
|
||||||
extractImages.selectText=추출된 이미지를 변환할 이미지 형식을 선택하세요.
|
extractImages.selectText=추출된 이미지를 변환할 이미지 형식을 선택하세요.
|
||||||
@@ -284,13 +590,17 @@ addImage.submit=이미지 추가
|
|||||||
#merge
|
#merge
|
||||||
merge.title=병합
|
merge.title=병합
|
||||||
merge.header=여러 개의 PDF 병합 (2개 이상)
|
merge.header=여러 개의 PDF 병합 (2개 이상)
|
||||||
|
merge.sortByName=Sort by name
|
||||||
|
merge.sortByDate=Sort by date
|
||||||
merge.submit=병합
|
merge.submit=병합
|
||||||
|
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=페이지 정렬 도구
|
pdfOrganiser.title=페이지 정렬 도구
|
||||||
pdfOrganiser.header=PDF 페이지 정렬
|
pdfOrganiser.header=PDF 페이지 정렬
|
||||||
pdfOrganiser.submit=페이지 재정렬
|
pdfOrganiser.submit=페이지 재정렬
|
||||||
|
|
||||||
|
|
||||||
#multiTool
|
#multiTool
|
||||||
multiTool.title=PDF 멀티 툴
|
multiTool.title=PDF 멀티 툴
|
||||||
multiTool.header=PDF 멀티 툴
|
multiTool.header=PDF 멀티 툴
|
||||||
@@ -302,6 +612,7 @@ pageRemover.header=PDF 페이지 제거 도구
|
|||||||
pageRemover.pagesToDelete=제거할 페이지 (쉼표로 구분된 페이지 번호 입력):
|
pageRemover.pagesToDelete=제거할 페이지 (쉼표로 구분된 페이지 번호 입력):
|
||||||
pageRemover.submit=페이지 제거
|
pageRemover.submit=페이지 제거
|
||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=PDF 회전
|
rotate.title=PDF 회전
|
||||||
rotate.header=PDF 회전
|
rotate.header=PDF 회전
|
||||||
@@ -309,8 +620,6 @@ rotate.selectAngle=회전 각도 선택 (90도의 배수로):
|
|||||||
rotate.submit=회전
|
rotate.submit=회전
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
split.title=PDF 분할
|
split.title=PDF 분할
|
||||||
split.header=PDF 분할
|
split.header=PDF 분할
|
||||||
@@ -326,31 +635,7 @@ split.splitPages=분할할 페이지 입력:
|
|||||||
split.submit=분할
|
split.submit=분할
|
||||||
|
|
||||||
|
|
||||||
#imageToPdf
|
#merge
|
||||||
imageToPDF.title=Image to PDF
|
|
||||||
imageToPDF.header=이미지를 PDF로 변환
|
|
||||||
imageToPDF.submit=변환
|
|
||||||
imageToPDF.selectText.1=맞춤 크기로 늘리기
|
|
||||||
imageToPDF.selectText.2=PDF 자동 회전
|
|
||||||
imageToPDF.selectText.3=다중 파일 로직 (여러 이미지로 작업하는 경우에만 활성화됨)
|
|
||||||
imageToPDF.selectText.4=단일 PDF로 병합
|
|
||||||
imageToPDF.selectText.5=별개의 PDF로 변환
|
|
||||||
|
|
||||||
#pdfToImage
|
|
||||||
pdfToImage.title=PDF to Image
|
|
||||||
pdfToImage.header=PDF를 이미지로 변환
|
|
||||||
pdfToImage.selectText=이미지 형식
|
|
||||||
pdfToImage.singleOrMultiple=이미지 결과 유형
|
|
||||||
pdfToImage.single=단일 큰 이미지
|
|
||||||
pdfToImage.multi=여러 이미지
|
|
||||||
pdfToImage.colorType=색상 유형
|
|
||||||
pdfToImage.color=컬러
|
|
||||||
pdfToImage.grey=그레이스케일
|
|
||||||
pdfToImage.blackwhite=흑백 (데이터 손실 가능성 있음!)
|
|
||||||
pdfToImage.submit=변환하기
|
|
||||||
|
|
||||||
|
|
||||||
#imageToPdf
|
|
||||||
imageToPDF.title=이미지를 PDF로 변환
|
imageToPDF.title=이미지를 PDF로 변환
|
||||||
imageToPDF.header=이미지를 PDF로 변환
|
imageToPDF.header=이미지를 PDF로 변환
|
||||||
imageToPDF.submit=변환하기
|
imageToPDF.submit=변환하기
|
||||||
@@ -360,6 +645,7 @@ imageToPDF.selectText.3=다중 파일 로직 (여러 이미지로 작업하는
|
|||||||
imageToPDF.selectText.4=단일 PDF로 병합
|
imageToPDF.selectText.4=단일 PDF로 병합
|
||||||
imageToPDF.selectText.5=별도의 PDF로 변환
|
imageToPDF.selectText.5=별도의 PDF로 변환
|
||||||
|
|
||||||
|
|
||||||
#pdfToImage
|
#pdfToImage
|
||||||
pdfToImage.title=PDF를 이미지로 변환
|
pdfToImage.title=PDF를 이미지로 변환
|
||||||
pdfToImage.header=PDF를 이미지로 변환
|
pdfToImage.header=PDF를 이미지로 변환
|
||||||
@@ -373,6 +659,7 @@ pdfToImage.grey=그레이스케일
|
|||||||
pdfToImage.blackwhite=흑백 (데이터 손실 가능성 있음!)
|
pdfToImage.blackwhite=흑백 (데이터 손실 가능성 있음!)
|
||||||
pdfToImage.submit=변환하기
|
pdfToImage.submit=변환하기
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=암호 추가
|
addPassword.title=암호 추가
|
||||||
addPassword.header=암호 추가 (암호화)
|
addPassword.header=암호 추가 (암호화)
|
||||||
@@ -394,6 +681,7 @@ addPassword.selectText.15=Restricts what can be done with the document once it i
|
|||||||
addPassword.selectText.16=Restricts the opening of the document itself<6C>
|
addPassword.selectText.16=Restricts the opening of the document itself<6C>
|
||||||
addPassword.submit=암호화
|
addPassword.submit=암호화
|
||||||
|
|
||||||
|
|
||||||
#watermark
|
#watermark
|
||||||
watermark.title=워터마크 추가
|
watermark.title=워터마크 추가
|
||||||
watermark.header=워터마크 추가
|
watermark.header=워터마크 추가
|
||||||
@@ -404,14 +692,10 @@ watermark.selectText.4=회전 각도 (0-360):
|
|||||||
watermark.selectText.5=가로 간격 (각 워터마크 사이의 가로 공간):
|
watermark.selectText.5=가로 간격 (각 워터마크 사이의 가로 공간):
|
||||||
watermark.selectText.6=세로 간격 (각 워터마크 사이의 세로 공간):
|
watermark.selectText.6=세로 간격 (각 워터마크 사이의 세로 공간):
|
||||||
watermark.selectText.7=투명도 (0% - 100%):
|
watermark.selectText.7=투명도 (0% - 100%):
|
||||||
|
watermark.selectText.8=Watermark Type:
|
||||||
|
watermark.selectText.9=Watermark Image:
|
||||||
watermark.submit=워터마크 추가
|
watermark.submit=워터마크 추가
|
||||||
|
|
||||||
#remove-watermark
|
|
||||||
remove-watermark.title=워터마크 제거
|
|
||||||
remove-watermark.header=워터마크 제거
|
|
||||||
remove-watermark.selectText.1=워터마크를 제거할 PDF 선택:
|
|
||||||
remove-watermark.selectText.2=워터마크 텍스트:
|
|
||||||
remove-watermark.submit=워터마크 제거
|
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=권한 변경
|
permissions.title=권한 변경
|
||||||
@@ -429,6 +713,7 @@ permissions.selectText.9=인쇄 방지
|
|||||||
permissions.selectText.10=다른 형식으로 인쇄 방지
|
permissions.selectText.10=다른 형식으로 인쇄 방지
|
||||||
permissions.submit=변경
|
permissions.submit=변경
|
||||||
|
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=암호 제거
|
removePassword.title=암호 제거
|
||||||
removePassword.header=암호 제거 (복호화)
|
removePassword.header=암호 제거 (복호화)
|
||||||
@@ -436,7 +721,9 @@ removePassword.selectText.1=복호화할 PDF 선택
|
|||||||
removePassword.selectText.2=암호
|
removePassword.selectText.2=암호
|
||||||
removePassword.submit=제거
|
removePassword.submit=제거
|
||||||
|
|
||||||
changeMetadata.title=메타데이터 변경
|
|
||||||
|
#changeMetadata
|
||||||
|
changeMetadata.title=제목:
|
||||||
changeMetadata.header=메타데이터 변경
|
changeMetadata.header=메타데이터 변경
|
||||||
changeMetadata.selectText.1=변경하려는 변수를 편집해주세요
|
changeMetadata.selectText.1=변경하려는 변수를 편집해주세요
|
||||||
changeMetadata.selectText.2=모든 메타데이터 삭제
|
changeMetadata.selectText.2=모든 메타데이터 삭제
|
||||||
@@ -454,27 +741,30 @@ changeMetadata.selectText.4=기타 메타데이터:
|
|||||||
changeMetadata.selectText.5=사용자 정의 메타데이터 항목 추가
|
changeMetadata.selectText.5=사용자 정의 메타데이터 항목 추가
|
||||||
changeMetadata.submit=변경
|
changeMetadata.submit=변경
|
||||||
|
|
||||||
|
|
||||||
|
#xlsToPdf
|
||||||
xlsToPdf.title=Excel to PDF
|
xlsToPdf.title=Excel to PDF
|
||||||
xlsToPdf.header=Excel을 PDF로 변환
|
xlsToPdf.header=Excel을 PDF로 변환
|
||||||
xlsToPdf.selectText.1=변환할 XLS 또는 XLSX Excel 시트 선택
|
xlsToPdf.selectText.1=변환할 XLS 또는 XLSX Excel 시트 선택
|
||||||
xlsToPdf.convert=변환하기
|
xlsToPdf.convert=변환하기
|
||||||
|
|
||||||
|
|
||||||
|
#pdfToPDFA
|
||||||
|
|
||||||
pdfToPDFA.title=PDF To PDF/A
|
pdfToPDFA.title=PDF To PDF/A
|
||||||
pdfToPDFA.header=PDF를 PDF/A로 변환
|
pdfToPDFA.header=PDF를 PDF/A로 변환
|
||||||
pdfToPDFA.credit=이 서비스는 PDF/A 변환을 위해 OCRmyPDF를 사용합니다.
|
pdfToPDFA.credit=이 서비스는 PDF/A 변환을 위해 OCRmyPDF를 사용합니다.
|
||||||
pdfToPDFA.submit=변환
|
pdfToPDFA.submit=변환
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToWord
|
||||||
PDFToWord.title=PDF to Word
|
PDFToWord.title=PDF to Word
|
||||||
PDFToWord.header=PDF를 Word로 변환
|
PDFToWord.header=PDF를 Word로 변환
|
||||||
PDFToWord.selectText.1=출력 파일 형식
|
PDFToWord.selectText.1=출력 파일 형식
|
||||||
PDFToWord.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
PDFToWord.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
||||||
PDFToWord.submit=변환
|
PDFToWord.submit=변환
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToPresentation
|
||||||
PDFToPresentation.title=PDF to Presentation
|
PDFToPresentation.title=PDF to Presentation
|
||||||
PDFToPresentation.header=PDF를 프레젠테이션으로 변환
|
PDFToPresentation.header=PDF를 프레젠테이션으로 변환
|
||||||
PDFToPresentation.selectText.1=출력 파일 형식
|
PDFToPresentation.selectText.1=출력 파일 형식
|
||||||
@@ -482,31 +772,23 @@ PDFToPresentation.credit=이 서비스는 파일 변환을 위해 LibreOffice를
|
|||||||
PDFToPresentation.submit=변환
|
PDFToPresentation.submit=변환
|
||||||
|
|
||||||
|
|
||||||
PDFToText.title=PDF to Text/RTF
|
#PDFToText
|
||||||
|
PDFToText.title=PDF to RTF (Text)
|
||||||
PDFToText.header=PDF를 텍스트/RTF로 변환
|
PDFToText.header=PDF를 텍스트/RTF로 변환
|
||||||
PDFToText.selectText.1=출력 파일 형식
|
PDFToText.selectText.1=출력 파일 형식
|
||||||
PDFToText.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
PDFToText.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
||||||
PDFToText.submit=변환
|
PDFToText.submit=변환
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToHTML
|
||||||
PDFToHTML.title=PDF to HTML
|
PDFToHTML.title=PDF to HTML
|
||||||
PDFToHTML.header=PDF를 HTML로 변환
|
PDFToHTML.header=PDF를 HTML로 변환
|
||||||
PDFToHTML.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
PDFToHTML.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
||||||
PDFToHTML.submit=변환
|
PDFToHTML.submit=변환
|
||||||
|
|
||||||
|
|
||||||
|
#PDFToXML
|
||||||
PDFToXML.title=PDF to XML
|
PDFToXML.title=PDF to XML
|
||||||
PDFToXML.header=PDF를 XML로 변환
|
PDFToXML.header=PDF를 XML로 변환
|
||||||
PDFToXML.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
PDFToXML.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
||||||
PDFToXML.submit=변환
|
PDFToXML.submit=변환
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user