Compare commits
108 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 | ||
|
|
f6262c82e1 |
6
.github/workflows/push-docker.yml
vendored
@@ -21,6 +21,8 @@ jobs:
|
||||
|
||||
|
||||
- uses: gradle/gradle-build-action@v2.4.2
|
||||
env:
|
||||
DOCKER_ENABLE_SECURITY: false
|
||||
with:
|
||||
gradle-version: 7.6
|
||||
arguments: clean build
|
||||
@@ -77,6 +79,8 @@ jobs:
|
||||
cache-to: type=gha,mode=max
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args:
|
||||
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
|
||||
|
||||
@@ -105,6 +109,8 @@ jobs:
|
||||
cache-to: type=gha,mode=max
|
||||
tags: ${{ steps.meta2.outputs.tags }}
|
||||
labels: ${{ steps.meta2.outputs.labels }}
|
||||
build-args:
|
||||
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
|
||||
|
||||
|
||||
22
.github/workflows/releaseArtifacts.yml
vendored
@@ -1,10 +1,20 @@
|
||||
name: Release Artifacts
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
enable_security: [true, false]
|
||||
include:
|
||||
- enable_security: true
|
||||
file_suffix: '-with-login'
|
||||
- enable_security: false
|
||||
file_suffix: ''
|
||||
steps:
|
||||
- uses: actions/checkout@v3.5.2
|
||||
|
||||
@@ -17,15 +27,17 @@ jobs:
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Generate jar
|
||||
- name: Generate jar (With Security=${{ matrix.enable_security }})
|
||||
run: ./gradlew clean createExe
|
||||
env:
|
||||
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./build/launch4j/Stirling-PDF.exe
|
||||
asset_name: Stirling-PDF.exe
|
||||
asset_name: Stirling-PDF${{ matrix.file_suffix }}.exe
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
@@ -33,13 +45,11 @@ jobs:
|
||||
id: versionNumber
|
||||
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
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
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 }}
|
||||
overwrite: true
|
||||
|
||||
|
||||
|
||||
4
.gitignore
vendored
@@ -19,7 +19,7 @@ pipeline/
|
||||
|
||||
#### Stirling-PDF Files ###
|
||||
customFiles/
|
||||
config/
|
||||
configs/
|
||||
watchedFolders/
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ watchedFolders/
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
*.db
|
||||
/build
|
||||
|
||||
/.vscode
|
||||
@@ -1,6 +1,11 @@
|
||||
# Build jbig2enc in a separate stage
|
||||
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
|
||||
RUN mkdir /scripts
|
||||
COPY ./scripts/* /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/
|
||||
RUN fc-cache -f -v
|
||||
|
||||
# Copy the application JAR file
|
||||
# Always copy the JAR
|
||||
COPY build/libs/*.jar app.jar
|
||||
|
||||
# Expose the application port
|
||||
@@ -19,8 +24,6 @@ EXPOSE 8080
|
||||
|
||||
# Set environment variables
|
||||
ENV APP_HOME_NAME="Stirling PDF"
|
||||
#ENV APP_HOME_DESCRIPTION="Personal PDF Website!"
|
||||
#ENV APP_NAVBAR_NAME="Stirling PDF"
|
||||
|
||||
# Run the application
|
||||
RUN chmod +x /scripts/init.sh
|
||||
|
||||
@@ -10,20 +10,17 @@ RUN apt-get update && \
|
||||
unoconv && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#Install fonts
|
||||
RUN mkdir /usr/share/fonts/opentype/noto/
|
||||
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
||||
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
|
||||
RUN fc-cache -f -v
|
||||
|
||||
# Copy the application JAR file
|
||||
COPY build/libs/*.jar app.jar
|
||||
|
||||
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8080
|
||||
|
||||
# Set environment variables
|
||||
ENV GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF
|
||||
ENV DOCKER_ENABLE_SECURITY=false
|
||||
|
||||
# Run the application
|
||||
CMD ["java", "-jar", "/app.jar"]
|
||||
|
||||
@@ -7,8 +7,11 @@ COPY build/libs/*.jar app.jar
|
||||
# Expose the application port
|
||||
EXPOSE 8080
|
||||
|
||||
|
||||
|
||||
# Set environment variables
|
||||
ENV GROUPS_TO_REMOVE=CLI
|
||||
ENV DOCKER_ENABLE_SECURITY=false
|
||||
|
||||
# Run the application
|
||||
CMD ["java", "-jar", "/app.jar"]
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ |
|
||||
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | |
|
||||
| crop | ✔️ | | | | | | | | | ✔️ | |
|
||||
| extract-page | ✔️ | | | | | | | | | ✔️ | |
|
||||
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
|
||||
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
|
||||
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
|
||||
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | |
|
||||
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
|
||||
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||
@@ -15,6 +17,7 @@
|
||||
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
|
||||
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
|
||||
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | |
|
||||
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
@@ -34,8 +37,10 @@
|
||||
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||
| extract-images | | | | ✔️ | | | | | | ✔️ | |
|
||||
| flatten | | | | ✔️ | | | | | | | |
|
||||
| flatten | | | | ✔️ | | | | | | | ✔️ |
|
||||
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | |
|
||||
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
|
||||
| show-javascript | | | | ✔️ | | | | | | | ✔️ |
|
||||
| sign | | | | ✔️ | | | | | | | ✔️ |
|
||||
36
README.md
@@ -178,27 +178,41 @@ Using the same method you can also change
|
||||
- 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
|
||||
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 (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
|
||||
|
||||
### Q1: Can you add authentication in Stirling PDF?
|
||||
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
|
||||
### Q1: What are your planned features?
|
||||
- Progress bar/Tracking
|
||||
- Full custom logic pipelines to combine multiple operations together.
|
||||
- Folder support with auto scanning to perform operations on
|
||||
- Redact sections of pages
|
||||
- Add page numbers
|
||||
- Auto rename (Renames file based on file title text)
|
||||
- URL to PDF
|
||||
- Change contrast
|
||||
- Redact text (Via UI)
|
||||
- Add Forms
|
||||
- Annotations
|
||||
- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
|
||||
- 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.
|
||||
|
||||
@@ -15,6 +15,7 @@ Operation | Ultra-Lite | Lite | Full
|
||||
--------------------|------------|------|-----
|
||||
add-page-numbers | ✔️ | ✔️ | ✔️
|
||||
add-password | ✔️ | ✔️ | ✔️
|
||||
add-image | ✔️ | ✔️ | ✔️
|
||||
add-watermark | ✔️ | ✔️ | ✔️
|
||||
adjust-contrast | ✔️ | ✔️ | ✔️
|
||||
auto-split-pdf | ✔️ | ✔️ | ✔️
|
||||
@@ -24,21 +25,25 @@ crop | ✔️ | ✔️ | ✔️
|
||||
change-metadata | ✔️ | ✔️ | ✔️
|
||||
change-permissions | ✔️ | ✔️ | ✔️
|
||||
compare | ✔️ | ✔️ | ✔️
|
||||
extract-page | ✔️ | ✔️ | ✔️
|
||||
extract-images | ✔️ | ✔️ | ✔️
|
||||
flatten | ✔️ | ✔️ | ✔️
|
||||
get-info-on-pdf | ✔️ | ✔️ | ✔️
|
||||
img-to-pdf | ✔️ | ✔️ | ✔️
|
||||
markdown-to-pdf | ✔️ | ✔️ | ✔️
|
||||
merge-pdfs | ✔️ | ✔️ | ✔️
|
||||
multi-page-layout | ✔️ | ✔️ | ✔️
|
||||
pdf-organizer | ✔️ | ✔️ | ✔️
|
||||
pdf-to-img | ✔️ | ✔️ | ✔️
|
||||
pdf-to-single-page | ✔️ | ✔️ | ✔️
|
||||
remove-pages | ✔️ | ✔️ | ✔️
|
||||
remove-password | ✔️ | ✔️ | ✔️
|
||||
rotate-pdf | ✔️ | ✔️ | ✔️
|
||||
sanitize-pdf | ✔️ | ✔️ | ✔️
|
||||
scale-pages | ✔️ | ✔️ | ✔️
|
||||
sign | ✔️ | ✔️ | ✔️
|
||||
show-javascript | ✔️ | ✔️ | ✔️
|
||||
split-pdfs | ✔️ | ✔️ | ✔️
|
||||
add-image | ✔️ | ✔️ | ✔️
|
||||
file-to-pdf | | ✔️ | ✔️
|
||||
pdf-to-html | | ✔️ | ✔️
|
||||
pdf-to-presentation | | ✔️ | ✔️
|
||||
|
||||
46
build.gradle
@@ -1,20 +1,38 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.1.1'
|
||||
id 'io.spring.dependency-management' version '1.1.0'
|
||||
id 'org.springframework.boot' version '3.1.2'
|
||||
id 'io.spring.dependency-management' version '1.1.2'
|
||||
id 'org.springdoc.openapi-gradle-plugin' version '1.6.0'
|
||||
id "io.swagger.swaggerhub" version "1.2.0"
|
||||
id 'edu.sc.seis.launch4j' version '3.0.3'
|
||||
}
|
||||
|
||||
group = 'stirling.software'
|
||||
version = '0.12.0'
|
||||
version = '0.13.0'
|
||||
sourceCompatibility = '17'
|
||||
|
||||
repositories {
|
||||
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 {
|
||||
apiDocsUrl = "http://localhost:8080/v3/api-docs"
|
||||
outputDir = file("$projectDir")
|
||||
@@ -45,9 +63,21 @@ launch4j {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web:3.1.0'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.1'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.0'
|
||||
implementation 'org.yaml:snakeyaml:2.1'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web:3.1.2'
|
||||
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
|
||||
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
|
||||
implementation 'commons-io:commons-io:2.13.0'
|
||||
@@ -55,7 +85,7 @@ dependencies {
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
|
||||
|
||||
//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:bcpkix-jdk15on:1.70'
|
||||
implementation 'com.itextpdf:itext7-core:7.2.5'
|
||||
@@ -64,6 +94,8 @@ dependencies {
|
||||
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")
|
||||
|
||||
|
||||
@@ -16,6 +16,16 @@ if [[ -n "$TESSERACT_LANGS" ]]; then
|
||||
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
|
||||
exec "$@"
|
||||
@@ -1,20 +1,20 @@
|
||||
package stirling.software.SPDF;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import stirling.software.SPDF.config.ConfigInitializer;
|
||||
import stirling.software.SPDF.utils.GeneralUtils;
|
||||
|
||||
@SpringBootApplication
|
||||
|
||||
//@EnableScheduling
|
||||
public class SPdfApplication {
|
||||
|
||||
@@ -48,7 +48,15 @@ public class SPdfApplication {
|
||||
}
|
||||
|
||||
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 {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
@@ -1,42 +1,54 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
@Bean(name = "appName")
|
||||
public String appName() {
|
||||
String appName = System.getProperty("APP_HOME_NAME");
|
||||
if (appName == null)
|
||||
appName = System.getenv("APP_HOME_NAME");
|
||||
return (appName != null) ? appName : "Stirling PDF";
|
||||
}
|
||||
|
||||
@Bean(name = "appVersion")
|
||||
public String appVersion() {
|
||||
String version = getClass().getPackage().getImplementationVersion();
|
||||
return (version != null) ? version : "0.0.0";
|
||||
}
|
||||
|
||||
@Bean(name = "homeText")
|
||||
public String homeText() {
|
||||
String homeText = System.getProperty("APP_HOME_DESCRIPTION");
|
||||
if (homeText == null)
|
||||
homeText = System.getenv("APP_HOME_DESCRIPTION");
|
||||
return (homeText != null) ? homeText : "null";
|
||||
}
|
||||
|
||||
@Bean(name = "navBarText")
|
||||
public String navBarText() {
|
||||
String navBarText = System.getProperty("APP_NAVBAR_NAME");
|
||||
if (navBarText == null)
|
||||
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";
|
||||
}
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Autowired
|
||||
ApplicationProperties applicationProperties;
|
||||
|
||||
@Bean(name = "loginEnabled")
|
||||
public boolean loginEnabled() {
|
||||
System.out.println(applicationProperties.toString());
|
||||
return applicationProperties.getSecurity().getEnableLogin();
|
||||
}
|
||||
|
||||
@Bean(name = "appName")
|
||||
public String appName() {
|
||||
String homeTitle = applicationProperties.getUi().getAppName();
|
||||
return (homeTitle != null) ? homeTitle : "Stirling PDF";
|
||||
}
|
||||
|
||||
@Bean(name = "appVersion")
|
||||
public String appVersion() {
|
||||
String version = getClass().getPackage().getImplementationVersion();
|
||||
return (version != null) ? version : "0.0.0";
|
||||
}
|
||||
|
||||
@Bean(name = "homeText")
|
||||
public String homeText() {
|
||||
return (applicationProperties.getUi().getHomeDescription() != null) ? applicationProperties.getUi().getHomeDescription() : "null";
|
||||
}
|
||||
|
||||
|
||||
@Bean(name = "navBarText")
|
||||
public String navBarText() {
|
||||
String defaultNavBar = applicationProperties.getUi().getAppNameNavbar() != null ? applicationProperties.getUi().getAppNameNavbar() : applicationProperties.getUi().getAppName();
|
||||
return (defaultNavBar != null) ? defaultNavBar : "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 org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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.SessionLocaleResolver;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
|
||||
@Configuration
|
||||
public class Beans implements WebMvcConfigurer {
|
||||
|
||||
|
||||
@Autowired
|
||||
ApplicationProperties applicationProperties;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(localeChangeInterceptor());
|
||||
@@ -29,10 +35,9 @@ public class Beans implements WebMvcConfigurer {
|
||||
@Bean
|
||||
public LocaleResolver localeResolver() {
|
||||
SessionLocaleResolver slr = new SessionLocaleResolver();
|
||||
|
||||
String appLocaleEnv = System.getProperty("APP_LOCALE");
|
||||
if (appLocaleEnv == null)
|
||||
appLocaleEnv = System.getenv("APP_LOCALE");
|
||||
|
||||
|
||||
String appLocaleEnv = applicationProperties.getSystem().getDefaultLocale();
|
||||
Locale defaultLocale = Locale.UK; // Fallback to UK locale if environment variable is not set
|
||||
|
||||
if (appLocaleEnv != null && !appLocaleEnv.isEmpty()) {
|
||||
|
||||
@@ -1,79 +1,70 @@
|
||||
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.List;
|
||||
import java.util.HashMap;
|
||||
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.ModelAndView;
|
||||
|
||||
public class CleanUrlInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints");
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null && !queryString.isEmpty()) {
|
||||
String requestURI = request.getRequestURI();
|
||||
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
|
||||
// Keep only the allowed parameters
|
||||
String[] queryParameters = queryString.split("&");
|
||||
for (String param : queryParameters) {
|
||||
String[] keyValue = param.split("=");
|
||||
if (keyValue.length != 2) {
|
||||
continue;
|
||||
}
|
||||
if (ALLOWED_PARAMS.contains(keyValue[0])) {
|
||||
parameters.put(keyValue[0], keyValue[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any parameters that are not allowed
|
||||
if (parameters.size() != queryParameters.length) {
|
||||
// Construct new query string
|
||||
StringBuilder newQueryString = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
if (newQueryString.length() > 0) {
|
||||
newQueryString.append("&");
|
||||
}
|
||||
newQueryString.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
}
|
||||
|
||||
// Redirect to the URL with only allowed query parameters
|
||||
String redirectUrl = requestURI + "?" + newQueryString;
|
||||
response.sendRedirect(redirectUrl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
ModelAndView modelAndView) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
}
|
||||
}
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public class CleanUrlInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints", "logout", "error", "file");
|
||||
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null && !queryString.isEmpty()) {
|
||||
String requestURI = request.getRequestURI();
|
||||
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
|
||||
// Keep only the allowed parameters
|
||||
String[] queryParameters = queryString.split("&");
|
||||
for (String param : queryParameters) {
|
||||
String[] keyValue = param.split("=");
|
||||
if (keyValue.length != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ALLOWED_PARAMS.contains(keyValue[0])) {
|
||||
parameters.put(keyValue[0], keyValue[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any parameters that are not allowed
|
||||
if (parameters.size() != queryParameters.length) {
|
||||
// Construct new query string
|
||||
StringBuilder newQueryString = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
if (newQueryString.length() > 0) {
|
||||
newQueryString.append("&");
|
||||
}
|
||||
newQueryString.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
}
|
||||
|
||||
// Redirect to the URL with only allowed query parameters
|
||||
String redirectUrl = requestURI + "?" + newQueryString;
|
||||
response.sendRedirect(redirectUrl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
ModelAndView modelAndView) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
@Service
|
||||
public class EndpointConfiguration {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
|
||||
private Map<String, Boolean> endpointStatuses = 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();
|
||||
processEnvironmentConfigs();
|
||||
}
|
||||
@@ -71,6 +79,8 @@ public class EndpointConfiguration {
|
||||
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
|
||||
addEndpointToGroup("Convert", "pdf-to-img");
|
||||
@@ -85,6 +95,7 @@ public class EndpointConfiguration {
|
||||
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
|
||||
addEndpointToGroup("Security", "add-password");
|
||||
@@ -94,7 +105,7 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Security", "cert-sign");
|
||||
addEndpointToGroup("Security", "sanitize-pdf");
|
||||
|
||||
|
||||
|
||||
// Adding endpoints to "Other" group
|
||||
addEndpointToGroup("Other", "ocr-pdf");
|
||||
addEndpointToGroup("Other", "add-image");
|
||||
@@ -109,7 +120,8 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Other", "compare");
|
||||
addEndpointToGroup("Other", "add-page-numbers");
|
||||
addEndpointToGroup("Other", "auto-rename");
|
||||
|
||||
addEndpointToGroup("Other", "get-info-on-pdf");
|
||||
addEndpointToGroup("Other", "show-javascript");
|
||||
|
||||
|
||||
|
||||
@@ -180,6 +192,11 @@ public class EndpointConfiguration {
|
||||
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
|
||||
addEndpointToGroup("Javascript", "pdf-organizer");
|
||||
@@ -189,21 +206,19 @@ public class EndpointConfiguration {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void processEnvironmentConfigs() {
|
||||
String endpointsToRemove = System.getenv("ENDPOINTS_TO_REMOVE");
|
||||
String groupsToRemove = System.getenv("GROUPS_TO_REMOVE");
|
||||
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
||||
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
||||
|
||||
if (endpointsToRemove != null) {
|
||||
String[] endpoints = endpointsToRemove.split(",");
|
||||
for (String endpoint : endpoints) {
|
||||
for (String endpoint : endpointsToRemove) {
|
||||
disableEndpoint(endpoint.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (groupsToRemove != null) {
|
||||
String[] groups = groupsToRemove.split(",");
|
||||
for (String group : groups) {
|
||||
for (String group : groupsToRemove) {
|
||||
disableGroup(group.trim());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class EndpointInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired
|
||||
private EndpointConfiguration endpointConfiguration;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
String requestURI = request.getRequestURI();
|
||||
if (!endpointConfiguration.isEndpointEnabled(requestURI)) {
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "This endpoint is disabled");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class EndpointInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired
|
||||
private EndpointConfiguration endpointConfiguration;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
String requestURI = request.getRequestURI();
|
||||
if (!endpointConfiguration.isEndpointEnabled(requestURI)) {
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "This endpoint is disabled");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
package stirling.software.SPDF.config;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
import io.micrometer.core.instrument.config.MeterFilterReply;
|
||||
|
||||
@Configuration
|
||||
public class MetricsConfig {
|
||||
|
||||
@Bean
|
||||
public MeterFilter meterFilter() {
|
||||
return new MeterFilter() {
|
||||
@Override
|
||||
public MeterFilterReply accept(Meter.Id id) {
|
||||
if (id.getName().equals("http.requests")) {
|
||||
return MeterFilterReply.NEUTRAL;
|
||||
}
|
||||
return MeterFilterReply.DENY;
|
||||
}
|
||||
};
|
||||
}
|
||||
package stirling.software.SPDF.config;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
import io.micrometer.core.instrument.config.MeterFilterReply;
|
||||
|
||||
@Configuration
|
||||
public class MetricsConfig {
|
||||
|
||||
@Bean
|
||||
public MeterFilter meterFilter() {
|
||||
return new MeterFilter() {
|
||||
@Override
|
||||
public MeterFilterReply accept(Meter.Id id) {
|
||||
if (id.getName().equals("http.requests")) {
|
||||
return MeterFilterReply.NEUTRAL;
|
||||
}
|
||||
return MeterFilterReply.DENY;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,48 +1,48 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class MetricsFilter extends OncePerRequestFilter {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
@Autowired
|
||||
public MetricsFilter(MeterRegistry meterRegistry) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
//System.out.println("uri="+uri + ", method=" + request.getMethod() );
|
||||
// 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"))) {
|
||||
Counter counter = Counter.builder("http.requests")
|
||||
.tag("uri", uri)
|
||||
.tag("method", request.getMethod())
|
||||
.register(meterRegistry);
|
||||
|
||||
counter.increment();
|
||||
//System.out.println("Counted");
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class MetricsFilter extends OncePerRequestFilter {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
@Autowired
|
||||
public MetricsFilter(MeterRegistry meterRegistry) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
//System.out.println("uri="+uri + ", method=" + request.getMethod() );
|
||||
// Ignore static resources
|
||||
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")
|
||||
.tag("uri", uri)
|
||||
.tag("method", request.getMethod())
|
||||
.register(meterRegistry);
|
||||
|
||||
counter.increment();
|
||||
//System.out.println("Counted");
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
|
||||
@Configuration
|
||||
public class OpenApiConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
String version = getClass().getPackage().getImplementationVersion();
|
||||
if (version == null) {
|
||||
Properties props = new Properties();
|
||||
try (InputStream input = getClass().getClassLoader().getResourceAsStream("version.properties")) {
|
||||
props.load(input);
|
||||
version = props.getProperty("version");
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
version = "1.0.0"; // default version if all else fails
|
||||
}
|
||||
}
|
||||
|
||||
return new OpenAPI().components(new Components()).info(
|
||||
new Info().title("Stirling PDF API").version(version).description("API documentation for all Server-Side processing.\nPlease note some functionality might be UI only and missing from here."));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
|
||||
@Configuration
|
||||
public class OpenApiConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
String version = getClass().getPackage().getImplementationVersion();
|
||||
if (version == null) {
|
||||
Properties props = new Properties();
|
||||
try (InputStream input = getClass().getClassLoader().getResourceAsStream("version.properties")) {
|
||||
props.load(input);
|
||||
version = props.getProperty("version");
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
version = "1.0.0"; // default version if all else fails
|
||||
}
|
||||
}
|
||||
|
||||
return new OpenAPI().components(new Components()).info(
|
||||
new Info().title("Stirling PDF API").version(version).description("API documentation for all Server-Side processing.\nPlease note some functionality might be UI only and missing from here."));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private EndpointInterceptor endpointInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
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
|
||||
}
|
||||
}
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private EndpointInterceptor endpointInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,11 @@
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
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.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
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.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.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
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.multipart.MultipartFile;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -60,20 +13,13 @@ 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.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.canvas.parser.EventType;
|
||||
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
|
||||
import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData;
|
||||
import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
|
||||
import com.itextpdf.kernel.pdf.canvas.parser.listener.IEventListener;
|
||||
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@@ -1,22 +1,29 @@
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
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.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||
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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@@ -26,55 +33,93 @@ public class MergeController {
|
||||
|
||||
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
|
||||
return mergedDoc;
|
||||
private Comparator<MultipartFile> getSortComparator(String sortType) {
|
||||
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")
|
||||
@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
|
||||
try (PDDocument mergedDoc = mergeDocuments(documents)) {
|
||||
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;
|
||||
} finally {
|
||||
for (PDDocument doc : documents) {
|
||||
if (doc != null) {
|
||||
doc.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +1,8 @@
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import com.itextpdf.kernel.pdf.*;
|
||||
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
|
||||
import com.itextpdf.kernel.geom.PageSize;
|
||||
import com.itextpdf.kernel.geom.Rectangle;
|
||||
import com.itextpdf.layout.Document;
|
||||
import com.itextpdf.layout.element.Image;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -24,12 +11,19 @@ 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;
|
||||
import org.apache.pdfbox.pdmodel.*;
|
||||
import org.apache.pdfbox.multipdf.PDFMergerUtility;
|
||||
@RestController
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class ToSinglePageController {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,36 +1,5 @@
|
||||
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.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;
|
||||
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.springframework.http.ResponseEntity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
@@ -41,6 +10,25 @@ 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 {
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
package stirling.software.SPDF.controller.api.converters;
|
||||
|
||||
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 org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -20,9 +11,6 @@ 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.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
|
||||
@@ -9,9 +9,7 @@ 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.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;
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package stirling.software.SPDF.controller.api.filters;
|
||||
|
||||
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.PDPage;
|
||||
@@ -17,11 +13,10 @@ 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.utils.PdfUtils;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Filter", description = "Filter APIs")
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package stirling.software.SPDF.controller.api.other;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -19,57 +20,7 @@ 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.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.PdfUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
import org.apache.pdfbox.pdmodel.*;
|
||||
import org.apache.pdfbox.pdmodel.common.*;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import io.swagger.v3.oas.annotations.*;
|
||||
import io.swagger.v3.oas.annotations.media.*;
|
||||
import io.swagger.v3.oas.annotations.parameters.*;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||
import org.apache.pdfbox.text.TextPosition;
|
||||
import org.apache.tomcat.util.http.ResponseUtil;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
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.PdfReader;
|
||||
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||
import com.itextpdf.kernel.pdf.PdfPage;
|
||||
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.media.Schema;
|
||||
|
||||
import java.io.*;
|
||||
import org.apache.pdfbox.pdmodel.*;
|
||||
import org.apache.pdfbox.text.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import io.swagger.v3.oas.annotations.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@RestController
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class AutoRenameController {
|
||||
|
||||
@@ -29,9 +29,9 @@ import com.google.zxing.PlanarYUVLuminanceSource;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
public class AutoSplitPdfController {
|
||||
|
||||
@@ -1,65 +1,39 @@
|
||||
package stirling.software.SPDF.controller.api.other;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
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.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.PdfUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
import org.apache.pdfbox.pdmodel.*;
|
||||
import org.apache.pdfbox.pdmodel.common.*;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import io.swagger.v3.oas.annotations.*;
|
||||
import io.swagger.v3.oas.annotations.media.*;
|
||||
import io.swagger.v3.oas.annotations.parameters.*;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||
import org.apache.tomcat.util.http.ResponseUtil;
|
||||
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.PdfReader;
|
||||
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||
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 java.io.*;
|
||||
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")
|
||||
@@ -116,7 +90,7 @@ public class PageNumbersController {
|
||||
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())) : String.valueOf(pageNumber);
|
||||
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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -3,8 +3,10 @@ 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;
|
||||
@@ -20,8 +22,7 @@ import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -47,6 +48,7 @@ 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;
|
||||
@@ -91,6 +93,10 @@ public class PipelineController {
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
ApplicationProperties applicationProperties;
|
||||
|
||||
|
||||
private void handleDirectory(Path dir) throws Exception {
|
||||
logger.info("Handling directory: {}", dir);
|
||||
Path jsonFile = dir.resolve(jsonFileName);
|
||||
@@ -182,8 +188,7 @@ public class PipelineController {
|
||||
// {filename} {folder} {date} {tmime} {pipeline}
|
||||
String outputDir = config.getOutputDir();
|
||||
|
||||
// Check if the environment variable 'automatedOutputFolder' is set
|
||||
String outputFolder = System.getenv("automatedOutputFolder");
|
||||
String outputFolder = applicationProperties.getAutoPipeline().getOutputFolder();
|
||||
|
||||
if (outputFolder == null || outputFolder.isEmpty()) {
|
||||
// If the environment variable is not set, use the default value
|
||||
|
||||
@@ -1,57 +1,22 @@
|
||||
package stirling.software.SPDF.controller.api.security;
|
||||
|
||||
import org.apache.pdfbox.cos.COSArray;
|
||||
import org.apache.pdfbox.cos.COSBase;
|
||||
import org.apache.pdfbox.cos.COSDictionary;
|
||||
import org.apache.pdfbox.cos.COSName;
|
||||
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.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
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.pdmodel.interactive.form.PDAcroForm;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
||||
|
||||
import com.itextpdf.kernel.pdf.PdfObject;
|
||||
import com.itextpdf.kernel.pdf.PdfOutline;
|
||||
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.PdfDocumentInfo;
|
||||
import com.itextpdf.kernel.pdf.PdfEncryption;
|
||||
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.PdfName;
|
||||
import com.itextpdf.kernel.pdf.PdfViewerPreferences;
|
||||
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||
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.annot.PdfWidgetAnnotation;
|
||||
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 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;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.apache.pdfbox.text.PDFTextStripper;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -60,17 +25,37 @@ import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
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 {
|
||||
@@ -193,11 +178,13 @@ public class GetInfoOnPDF {
|
||||
if (embeddedFiles != null) {
|
||||
|
||||
PdfArray namesArray = embeddedFiles.getAsArray(PdfName.Names);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -224,15 +211,33 @@ public class GetInfoOnPDF {
|
||||
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();
|
||||
jsNode.put("JS Name", namesArray.getAsString(i).toString());
|
||||
jsNode.put("JS Code", namesArray.getAsString(i + 1).toString());
|
||||
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);
|
||||
@@ -305,16 +310,15 @@ public class GetInfoOnPDF {
|
||||
}
|
||||
other.set("Bookmarks/Outline/TOC", bookmarksArray);
|
||||
|
||||
byte[] xmpBytes = itextDoc.getXmpMetadata();
|
||||
String xmpString = null;
|
||||
try {
|
||||
byte[] xmpBytes = itextDoc.getXmpMetadata();
|
||||
if (xmpBytes != null) {
|
||||
if (xmpBytes != null) {
|
||||
try {
|
||||
XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(xmpBytes);
|
||||
xmpString = xmpMeta.dumpObject();
|
||||
|
||||
xmpString = new String(XMPMetaFactory.serializeToBuffer(xmpMeta, new SerializeOptions()));
|
||||
} catch (XMPException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (XMPException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
other.put("XMPMetadata", xmpString);
|
||||
|
||||
@@ -416,8 +420,10 @@ public class GetInfoOnPDF {
|
||||
for (PdfAnnotation annotation : annotations) {
|
||||
if (annotation instanceof PdfLinkAnnotation) {
|
||||
PdfLinkAnnotation linkAnnotation = (PdfLinkAnnotation) annotation;
|
||||
String uri = linkAnnotation.getAction().toString();
|
||||
uniqueURIs.add(uri); // Add to set to ensure uniqueness
|
||||
if(linkAnnotation != null && linkAnnotation.getAction() != null) {
|
||||
String uri = linkAnnotation.getAction().toString();
|
||||
uniqueURIs.add(uri); // Add to set to ensure uniqueness
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,13 +52,13 @@ public class PasswordController {
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to which the password should be added", required = true)
|
||||
MultipartFile fileInput,
|
||||
@RequestParam(value = "", 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)")
|
||||
String ownerPassword,
|
||||
@RequestParam( name = "password", required = false)
|
||||
@RequestParam( name = "password", required = false, defaultValue = "")
|
||||
@Parameter(description = "The password to be added to the PDF file (Restricts the opening of the document itself.)")
|
||||
String password,
|
||||
@RequestParam( name = "keyLength", required = false)
|
||||
@RequestParam( name = "keyLength", required = false, defaultValue = "256")
|
||||
@Parameter(description = "The length of the encryption key", schema = @Schema(allowableValues = {"40", "128", "256"}))
|
||||
int keyLength,
|
||||
@RequestParam( name = "canAssembleDocument", required = false)
|
||||
@@ -98,15 +98,15 @@ public class PasswordController {
|
||||
ap.setCanPrint(!canPrint);
|
||||
ap.setCanPrintFaithful(!canPrintFaithful);
|
||||
StandardProtectionPolicy spp = new StandardProtectionPolicy(ownerPassword, password, ap);
|
||||
|
||||
|
||||
|
||||
spp.setEncryptionKeyLength(keyLength);
|
||||
|
||||
if(!"".equals(ownerPassword) || !"".equals(password)) {
|
||||
spp.setEncryptionKeyLength(keyLength);
|
||||
}
|
||||
spp.setPermissions(ap);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +1,35 @@
|
||||
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.PDResources;
|
||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||
import org.apache.pdfbox.pdmodel.PDResources;
|
||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||
import org.apache.pdfbox.pdmodel.common.PDStream;
|
||||
import org.apache.pdfbox.pdmodel.interactive.action.*;
|
||||
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.apache.pdfbox.pdmodel.interactive.form.PDNonTerminalField;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
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.media.Schema;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@RestController
|
||||
public class SanitizeController {
|
||||
|
||||
@@ -35,19 +40,19 @@ public class SanitizeController {
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to be sanitized")
|
||||
MultipartFile inputFile,
|
||||
@RequestParam(name = "removeJavaScript", required = false, defaultValue = "true")
|
||||
@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 = "true")
|
||||
@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 = "true")
|
||||
@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 = "true")
|
||||
@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 = "true")
|
||||
@RequestParam(name = "removeFonts", required = false, defaultValue = "false")
|
||||
@Parameter(description = "Remove fonts from the PDF if set to true")
|
||||
Boolean removeFonts) throws IOException {
|
||||
|
||||
@@ -75,8 +80,24 @@ public class SanitizeController {
|
||||
return WebResponseUtils.pdfDocToWebResponse(document, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_sanitized.pdf");
|
||||
}
|
||||
}
|
||||
private void sanitizeJavaScript(PDDocument document) throws IOException {
|
||||
for (PDPage page : document.getPages()) {
|
||||
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;
|
||||
@@ -89,13 +110,28 @@ public class SanitizeController {
|
||||
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
|
||||
if (acroForm != null) {
|
||||
for (PDField field : acroForm.getFields()) {
|
||||
if (field.getActions().getF() instanceof PDActionJavaScript) {
|
||||
field.getActions().setF(null);
|
||||
}
|
||||
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();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package stirling.software.SPDF.controller.api.security;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -32,9 +30,9 @@ 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.utils.WebResponseUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Security", description = "Security APIs")
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -24,10 +24,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@Controller
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class GeneralWebController {
|
||||
|
||||
|
||||
|
||||
|
||||
@GetMapping("/pipeline")
|
||||
@Hidden
|
||||
public String pipelineForm(Model model) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package stirling.software.SPDF.controller.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
@@ -7,6 +8,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
|
||||
@Controller
|
||||
public class HomeWebController {
|
||||
@@ -31,18 +33,16 @@ public class HomeWebController {
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
ApplicationProperties applicationProperties;
|
||||
|
||||
|
||||
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@ResponseBody
|
||||
@Hidden
|
||||
public String getRobotsTxt() {
|
||||
String allowGoogleVisibility = System.getProperty("ALLOW_GOOGLE_VISIBILITY");
|
||||
if (allowGoogleVisibility == null)
|
||||
allowGoogleVisibility = System.getenv("ALLOW_GOOGLE_VISIBILITY");
|
||||
if (allowGoogleVisibility == null)
|
||||
allowGoogleVisibility = "false";
|
||||
if (Boolean.parseBoolean(allowGoogleVisibility)) {
|
||||
Boolean allowGoogle = applicationProperties.getSystem().getGooglevisibility();
|
||||
if(Boolean.TRUE.equals(allowGoogle)) {
|
||||
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nAllow: /";
|
||||
} else {
|
||||
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
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.RequestMapping;
|
||||
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.Parameter;
|
||||
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
|
||||
@RequestMapping("/api/v1")
|
||||
@Tag(name = "API", description = "Info APIs")
|
||||
public class MetricsController {
|
||||
|
||||
|
||||
@Autowired
|
||||
ApplicationProperties applicationProperties;
|
||||
|
||||
|
||||
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) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
@@ -29,18 +55,25 @@ public class MetricsController {
|
||||
@GetMapping("/status")
|
||||
@Operation(summary = "Application status and version",
|
||||
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<>();
|
||||
status.put("status", "UP");
|
||||
status.put("version", getClass().getPackage().getImplementationVersion());
|
||||
return status;
|
||||
return ResponseEntity.ok(status);
|
||||
}
|
||||
|
||||
@GetMapping("/loads")
|
||||
@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.")
|
||||
public Double getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||
try {
|
||||
public ResponseEntity<?> getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||
if (!metricsEnabled) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||
}
|
||||
try {
|
||||
|
||||
double count = 0.0;
|
||||
|
||||
@@ -68,36 +101,165 @@ public class MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return ResponseEntity.ok(count);
|
||||
} 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")
|
||||
@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.")
|
||||
public Double getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||
try {
|
||||
Counter counter;
|
||||
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;
|
||||
public ResponseEntity<?> getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||
if (!metricsEnabled) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,15 @@ public class OtherWebController {
|
||||
modelAndView.addObject("currentPage", "extract-image-scans");
|
||||
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) {
|
||||
|
||||
@@ -11,6 +11,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@Tag(name = "Security", description = "Security APIs")
|
||||
public class SecurityWebController {
|
||||
|
||||
@GetMapping("/auto-redact")
|
||||
@Hidden
|
||||
public String autoRedactForm(Model model) {
|
||||
model.addAttribute("currentPage", "auto-redact");
|
||||
return "security/auto-redact";
|
||||
}
|
||||
|
||||
@GetMapping("/add-password")
|
||||
@Hidden
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
}
|
||||
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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -32,10 +32,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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;
|
||||
|
||||
public class PdfUtils {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,19 +17,29 @@ server.error.include-exception=true
|
||||
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.context-path=${APP_ROOT_PATH:/}
|
||||
server.servlet.context-path=${SYSTEM_ROOTURIPATH:/}
|
||||
|
||||
spring.devtools.restart.enabled=true
|
||||
spring.devtools.livereload.enabled=true
|
||||
|
||||
spring.thymeleaf.encoding=UTF-8
|
||||
|
||||
server.connection-timeout=${CONNECTION_TIMEOUT:5m}
|
||||
spring.mvc.async.request-timeout=${ASYNC_CONNECTION_TIMEOUT:300000}
|
||||
server.connection-timeout=${SYSTEM_CONNECTIONTIMEOUTMINUTES:5m}
|
||||
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.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
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ settings.downloadOption.1=\u0641\u062A\u062D \u0641\u064A \u0646\u0641\u0633 \u0
|
||||
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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=إضافة صورة
|
||||
#merge
|
||||
merge.title=دمج
|
||||
merge.header=دمج ملفات PDF متعددة (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=دمج
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=دوران (0-360):
|
||||
watermark.selectText.5=widthSpacer (مسافة بين كل علامة مائية أفقيًا):
|
||||
watermark.selectText.6=heightSpacer (مسافة بين كل علامة مائية عموديًا):
|
||||
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=إضافة علامة مائية
|
||||
|
||||
|
||||
#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
|
||||
permissions.title=تغيير الأذونات
|
||||
permissions.header=تغيير الأذونات
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Afegir Imatge
|
||||
#merge
|
||||
merge.title=Fusiona
|
||||
merge.header=Fusiona múltiples PDFs (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Fusiona
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Rotació (0-360):
|
||||
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.7=Opacitat (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
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
|
||||
permissions.title=Canviar Permissos
|
||||
permissions.header=Canviar Permissos
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Bild hinzufügen
|
||||
#merge
|
||||
merge.title=Zusammenführen
|
||||
merge.header=Mehrere PDFs zusammenführen (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Zusammenführen
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Drehung (0-360):
|
||||
watermark.selectText.5=breiteSpacer (horizontaler Abstand zwischen den einzelnen Wasserzeichen):
|
||||
watermark.selectText.6=höheSpacer (vertikaler Abstand zwischen den einzelnen Wasserzeichen):
|
||||
watermark.selectText.7=Deckkraft (0% - 100 %):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
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
|
||||
permissions.title=Berechtigungen ändern
|
||||
permissions.header=Berechtigungen ändern
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -255,13 +294,47 @@ 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
|
||||
@@ -326,6 +399,9 @@ 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
|
||||
|
||||
|
||||
@@ -511,6 +587,8 @@ 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
|
||||
|
||||
|
||||
@@ -569,9 +647,9 @@ imageToPDF.selectText.5=Convert to separate PDFs
|
||||
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.singleOrMultiple=Page to Image result type
|
||||
pdfToImage.single=Single Big Image Combing all pages
|
||||
pdfToImage.multi=Multiple Images, one image per page
|
||||
pdfToImage.colorType=Colour type
|
||||
pdfToImage.color=Colour
|
||||
pdfToImage.grey=Greyscale
|
||||
@@ -611,17 +689,11 @@ 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
|
||||
|
||||
|
||||
#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
|
||||
permissions.title=Change Permissions
|
||||
permissions.header=Change Permissions
|
||||
|
||||
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
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Convierte cualquier archivo HTML o ZIP a PDF
|
||||
HTMLToPDF.tags=margen,contenido web,transformación,convertir
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ addPageNumbers.selectText.3=Posición
|
||||
addPageNumbers.selectText.4=Número de inicio
|
||||
addPageNumbers.selectText.5=Páginas a numerar
|
||||
addPageNumbers.selectText.6=Texto personalizado
|
||||
addPageNumbers.customTextDesc=Custom Text
|
||||
addPageNumbers.numberPagesDesc=Which pages to number, default 'all', also accepts 1-5 or 2,5,9 etc
|
||||
addPageNumbers.customNumberDesc=Defaults to {n}, also accepts 'Page {n} of {total}', 'Text-{n}', '{filename}-{n}
|
||||
addPageNumbers.submit=Añadir Números de Página
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Añadir imagen
|
||||
#merge
|
||||
merge.title=Unir
|
||||
merge.header=Unir múltiples PDFs (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Unir
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Rotación (0-360):
|
||||
watermark.selectText.5=Ancho (Espacio entre cada marca de agua horizontalmente):
|
||||
watermark.selectText.6=Alto (Espacio entre cada marca de agua verticalmente):
|
||||
watermark.selectText.7=Opacidad (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.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
|
||||
permissions.title=Cambiar permisos
|
||||
permissions.header=Cambiar permisos
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Gehitu irudia
|
||||
#merge
|
||||
merge.title=Elkartu
|
||||
merge.header=Elkartu zenbait PDF (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Elkartu
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Errotazioa (0-360):
|
||||
watermark.selectText.5=Zabalera (ur-marka bakoitzaren arteko espazioa horizontalean):
|
||||
watermark.selectText.6=Altuera (ur-marka bakoitzaren arteko espazioa bertikalean):
|
||||
watermark.selectText.7=Opakutasuna (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
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
|
||||
permissions.title=Aldatu baimenak
|
||||
permissions.header=Aldatu baimenak
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Aggiungi immagine
|
||||
#merge
|
||||
merge.title=Unisci
|
||||
merge.header=Unisci 2 o più PDF
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Unisci
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Rotazione (0-360):
|
||||
watermark.selectText.5=spazio orizzontale (tra ogni filigrana):
|
||||
watermark.selectText.6=spazio verticale (tra ogni filigrana):
|
||||
watermark.selectText.7=Opacità (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
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
|
||||
permissions.title=Cambia Permessi
|
||||
permissions.header=Cambia permessi
|
||||
|
||||
@@ -31,7 +31,11 @@ sizes.medium=Medium
|
||||
sizes.large=Large
|
||||
sizes.x-large=X-Large
|
||||
error.pdfPassword=PDFにパスワードが設定されてますが、パスワードが入力されてないか間違ってます。
|
||||
|
||||
delete=Delete
|
||||
username=Username
|
||||
password=Password
|
||||
welcome=Welcome
|
||||
=Property
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=画像の追加
|
||||
#merge
|
||||
merge.title=結合
|
||||
merge.header=複数のPDFを結合 (2ファイル以上)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=結合
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=回転 (0-360):
|
||||
watermark.selectText.5=幅スペース (各透かし間の水平方向のスペース):
|
||||
watermark.selectText.6=高さスペース (各透かし間の垂直方向のスペース):
|
||||
watermark.selectText.7=不透明度 (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.submit=透かしを追加
|
||||
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=透かしの削除
|
||||
remove-watermark.header=透かしの削除
|
||||
remove-watermark.selectText.1=透かしを削除するPDFを選択:
|
||||
remove-watermark.selectText.2=透かしのテキスト:
|
||||
remove-watermark.submit=透かしを削除
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=権限の変更
|
||||
permissions.header=権限の変更
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=이미지 추가
|
||||
#merge
|
||||
merge.title=병합
|
||||
merge.header=여러 개의 PDF 병합 (2개 이상)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=병합
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=회전 각도 (0-360):
|
||||
watermark.selectText.5=가로 간격 (각 워터마크 사이의 가로 공간):
|
||||
watermark.selectText.6=세로 간격 (각 워터마크 사이의 세로 공간):
|
||||
watermark.selectText.7=투명도 (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.submit=워터마크 추가
|
||||
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=워터마크 제거
|
||||
remove-watermark.header=워터마크 제거
|
||||
remove-watermark.selectText.1=워터마크를 제거할 PDF 선택:
|
||||
remove-watermark.selectText.2=워터마크 텍스트:
|
||||
remove-watermark.submit=워터마크 제거
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=권한 변경
|
||||
permissions.header=권한 변경
|
||||
|
||||
794
src/main/resources/messages_nl_NL.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=Selecteer PDF(s)
|
||||
multiPdfPrompt=Selecteer PDFs (2+)
|
||||
multiPdfDropPrompt=Selecteer (of sleep & zet neer) alle PDFs die je nodig hebt
|
||||
imgPrompt=Selecteer afbeelding(en)
|
||||
genericSubmit=Indienen
|
||||
processTimeWarning=Waarschuwing: Dit proces kan tot een minuut duren afhankelijk van de bestandsgrootte
|
||||
pageOrderPrompt=Aangepaste pagina volgorde (Voer een komma-gescheiden lijst van paginanummers of functies in, zoals 2n+1) :
|
||||
goToPage=Ga
|
||||
true=Waar
|
||||
false=Onwaar
|
||||
unknown=Onbekend
|
||||
save=Opslaan
|
||||
close=Sluiten
|
||||
filesSelected=Bestanden geselecteerd
|
||||
noFavourites=Geen favorieten toegevoegd
|
||||
bored=Verveeld met wachten?
|
||||
alphabet=Alfabet
|
||||
downloadPdf=Download PDF
|
||||
text=Tekst
|
||||
font=Lettertype
|
||||
selectFillter=-- Selecteer --
|
||||
pageNum=Paginanummer
|
||||
sizes.small=Klein
|
||||
sizes.medium=Medium
|
||||
sizes.large=Groot
|
||||
sizes.x-large=Extra Groot
|
||||
error.pdfPassword=Het PDF document is beveiligd met een wachtwoord en het wachtwoord is niet ingevoerd of was onjuist
|
||||
delete=Verwijderen
|
||||
username=Gebruikersnaam
|
||||
password=Wachtwoord
|
||||
welcome=Welkom
|
||||
=Property
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.convert=Converteren
|
||||
navbar.security=Beveiliging
|
||||
navbar.other=Overige
|
||||
navbar.darkmode=Donkere modus
|
||||
navbar.pageOps=Pagina operaties
|
||||
navbar.settings=Instellingen
|
||||
|
||||
#############
|
||||
# SETTINGS #
|
||||
#############
|
||||
settings.title=Instellingen
|
||||
settings.update=Update beschikbaar
|
||||
settings.appVersion=App versie:
|
||||
settings.downloadOption.title=Kies download optie (Voor enkelvoudige bestanddownloads zonder zip):
|
||||
settings.downloadOption.1=Open in hetzelfde venster
|
||||
settings.downloadOption.2=Open in nieuw venster
|
||||
settings.downloadOption.3=Download bestand
|
||||
settings.zipThreshold=Zip bestanden wanneer het aantal gedownloade bestanden overschrijdt
|
||||
settings.signOut=Uitloggen
|
||||
settings.accountSettings=Account instellingen
|
||||
|
||||
account.title=Account instellingen
|
||||
account.accountSettings=Account instellingen
|
||||
account.adminSettings=Beheerdersinstellingen - Gebruikers bekijken en toevoegen
|
||||
account.userControlSettings=Gebruikerscontrole instellingen
|
||||
account.changeUsername=Wijzig gebruikersnaam
|
||||
account.changeUsername=Wijzig gebruikersnaam
|
||||
account.password=Bevestigingswachtwoord
|
||||
account.oldPassword=Oud wachtwoord
|
||||
account.newPassword=Nieuw wachtwoord
|
||||
account.changePassword=Wijzig wachtwoord
|
||||
account.confirmNewPassword=Bevestig nieuw wachtwoord
|
||||
account.signOut=Uitloggen
|
||||
account.yourApiKey=Jouw API sleutel
|
||||
account.syncTitle=Synchroniseer browserinstellingen met account
|
||||
account.settingsCompare=Instellingen vergelijking:
|
||||
account.property=Eigenschap
|
||||
account.webBrowserSettings=Web Browser instelling
|
||||
account.syncToBrowser=Synchroniseer account -> browser
|
||||
account.syncToAccount=Synchroniseer account <- browser
|
||||
|
||||
|
||||
adminUserSettings.title=Gebruikerscontrole instellingen
|
||||
adminUserSettings.header=Beheer Gebruikerscontrole instellingen
|
||||
adminUserSettings.admin=Beheerder
|
||||
adminUserSettings.user=Gebruiker
|
||||
adminUserSettings.addUser=Voeg nieuwe gebruiker toe
|
||||
adminUserSettings.roles=Rollen
|
||||
adminUserSettings.role=Rol
|
||||
adminUserSettings.actions=Acties
|
||||
adminUserSettings.apiUser=Beperkte API gebruiker
|
||||
adminUserSettings.webOnlyUser=Alleen web gebruiker
|
||||
adminUserSettings.submit=Sla gebruiker op
|
||||
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
home.desc=Jouw lokaal gehoste one-stop-shop voor al je PDF-behoeften.
|
||||
|
||||
|
||||
home.multiTool.title=PDF Multitool
|
||||
home.multiTool.desc=Samenvoegen, draaien, herschikken en pagina''s verwijderen
|
||||
multiTool.tags=Multitool,Multi bewerking,UI,klik sleep,voorkant,clientzijde,interactief,beweegbaar,verplaats
|
||||
|
||||
home.merge.title=Samenvoegen
|
||||
home.merge.desc=Voeg eenvoudig meerdere PDF''s samen tot één.
|
||||
merge.tags=samenvoegen,Pagina operaties,Serverkant
|
||||
|
||||
home.split.title=Splitsen
|
||||
home.split.desc=Splits PDF''s in meerdere documenten
|
||||
split.tags=Pagina operaties,verdelen,meerdere pagina''s,knippen,serverzijde
|
||||
|
||||
home.rotate.title=Roteren
|
||||
home.rotate.desc=Roteer eenvoudig je PDF''s.
|
||||
rotate.tags=serverzijde
|
||||
|
||||
|
||||
home.imageToPdf.title=Afbeelding naar PDF
|
||||
home.imageToPdf.desc=Converteer een afbeelding (PNG, JPEG, GIF) naar PDF.
|
||||
imageToPdf.tags=conversie,img,jpg,foto
|
||||
|
||||
home.pdfToImage.title=PDF naar Afbeelding
|
||||
home.pdfToImage.desc=Converteer een PDF naar een afbeelding. (PNG, JPEG, GIF)
|
||||
pdfToImage.tags=conversie,img,jpg,foto
|
||||
|
||||
home.pdfOrganiser.title=Organiseren
|
||||
home.pdfOrganiser.desc=Verwijder/Herschik pagina''s in een volgorde naar keus
|
||||
pdfOrganiser.tags=duplex,even oneven,sorteren,verplaatsen
|
||||
|
||||
|
||||
home.addImage.title=Afbeelding toevoegen
|
||||
home.addImage.desc=Voegt een afbeelding toe op een specifieke locatie in de PDF
|
||||
addImage.tags=img,jpg,foto
|
||||
|
||||
home.watermark.title=Watermerk toevoegen
|
||||
home.watermark.desc=Voeg een aangepast watermerk toe aan je PDF-document.
|
||||
watermark.tags=Tekst,herhalend,label,eigen,copyright,handelsmerk,img,jpg,foto
|
||||
|
||||
home.permissions.title=Permissies wijzigen
|
||||
home.permissions.desc=Wijzig de permissies van je PDF-document
|
||||
permissions.tags=lezen,schrijven,bewerken,printen
|
||||
|
||||
|
||||
home.removePages.title=Verwijderen
|
||||
home.removePages.desc=Verwijder ongewenste pagina''s uit je PDF-document.
|
||||
removePages.tags=Pagina''s verwijderen
|
||||
|
||||
home.addPassword.title=Wachtwoord toevoegen
|
||||
home.addPassword.desc=Versleutel je PDF-document met een wachtwoord.
|
||||
addPassword.tags=veilig,beveiliging
|
||||
|
||||
home.removePassword.title=Wachtwoord verwijderen
|
||||
home.removePassword.desc=Verwijder wachtwoordbeveiliging van je PDF-document.
|
||||
removePassword.tags=veilig,Decrypteren,beveiliging,wachtwoord verwijderen
|
||||
|
||||
home.compressPdfs.title=Comprimeren
|
||||
home.compressPdfs.desc=Comprimeer PDFs om hun bestandsgrootte te verkleinen.
|
||||
compressPdfs.tags=comprimeren,klein
|
||||
|
||||
|
||||
home.changeMetadata.title=Metadata wijzigen
|
||||
home.changeMetadata.desc=Wijzig/Verwijder/Voeg metadata toe van een PDF-document
|
||||
changeMetadata.tags=Titel,auteur,datum,creatie,tijd,uitgever,producent,statistieken
|
||||
|
||||
home.fileToPDF.title=Bestand naar PDF converteren
|
||||
home.fileToPDF.desc=Converteer bijna ieder bestand naar PDF (DOCX, PNG, XLS, PPT, TXT en meer)
|
||||
fileToPDF.tags=transformatie,formaat,document,foto,slide,tekst,conversie,kantoor,docs,word,excel,powerpoint
|
||||
|
||||
home.ocr.title=OCR / Scans opruimen
|
||||
home.ocr.desc=Ruim scans op, detecteert tekst van afbeeldingen in een PDF en voegt deze opnieuw toe als tekst.
|
||||
ocr.tags=herkenning,tekst,afbeelding,scan,lezen,identificeren,detectie,bewerkbaar
|
||||
|
||||
|
||||
home.extractImages.title=Afbeeldingen extraheren
|
||||
home.extractImages.desc=Extraheert alle afbeeldingen uit een PDF en slaat ze op in een zip
|
||||
extractImages.tags=foto,opslaan,archief,zip,vastleggen,plukken
|
||||
|
||||
home.pdfToPDFA.title=PDF naar PDF/A
|
||||
home.pdfToPDFA.desc=Converteer PDF naar PDF/A voor langdurige opslag
|
||||
pdfToPDFA.tags=archief,langdurig,standaard,conversie,opslag,bewaring
|
||||
|
||||
home.PDFToWord.title=PDF naar Word
|
||||
home.PDFToWord.desc=Converteer PDF naar Word-formaten (DOC, DOCX en ODT)
|
||||
PDFToWord.tags=doc,docx,odt,word,transformatie,formaat,conversie,kantoor,microsoft,docfile
|
||||
|
||||
home.PDFToPresentation.title=PDF naar Presentatie
|
||||
home.PDFToPresentation.desc=Converteer PDF naar Presentatie formaten (PPT, PPTX en ODP)
|
||||
PDFToPresentation.tags=slides,show,kantoor,microsoft
|
||||
|
||||
home.PDFToText.title=PDF naar RTF (Tekst)
|
||||
home.PDFToText.desc=Converteer PDF naar Tekst of RTF formaat
|
||||
PDFToText.tags=rijkformaat
|
||||
|
||||
home.PDFToHTML.title=PDF naar HTML
|
||||
home.PDFToHTML.desc=Converteer PDF naar HTML formaat
|
||||
PDFToHTML.tags=webinhoud,browser vriendelijk
|
||||
|
||||
|
||||
home.PDFToXML.title=PDF naar XML
|
||||
home.PDFToXML.desc=Converteer PDF naar XML formaat
|
||||
PDFToXML.tags=data-extractie,gestructureerd,code
|
||||
|
||||
home.ScannerImageSplit.title=Detecteer/Split gescande foto''s
|
||||
home.ScannerImageSplit.desc=Splits meerdere foto''s van binnen een foto/PDF
|
||||
ScannerImageSplit.tags=scheiden,auto-detecteren,scans,meer-foto,organiseren
|
||||
|
||||
home.sign.title=Ondertekenen
|
||||
home.sign.desc=Voegt handtekening toe aan PDF via tekenen, tekst of afbeelding
|
||||
sign.tags=autoriseren,initialen,getekende-handtekening,tekst-handtekening,afbeelding-handtekening
|
||||
|
||||
home.flatten.title=Platdrukken
|
||||
home.flatten.desc=Verwijder alle interactieve elementen en formulieren uit een PDF
|
||||
flatten.tags=statisch,deactiveren,niet-interactief,stroomlijnen
|
||||
|
||||
home.repair.title=Repareren
|
||||
home.repair.desc=Probeert een corrupt/beschadigd PDF te herstellen
|
||||
repair.tags=repareren,herstellen,correctie,terughalen
|
||||
|
||||
home.removeBlanks.title=Verwijder lege pagina''s
|
||||
home.removeBlanks.desc=Detecteert en verwijdert lege pagina''s uit een document
|
||||
removeBlanks.tags=opruimen,stroomlijnen,geen-inhoud,organiseren
|
||||
|
||||
home.compare.title=Vergelijken
|
||||
home.compare.desc=Vergelijkt en toont de verschillen tussen 2 PDF-documenten
|
||||
compare.tags=onderscheiden,contrasteren,veranderingen,analyse
|
||||
|
||||
home.certSign.title=Ondertekenen met certificaat
|
||||
home.certSign.desc=Ondertekent een PDF met een certificaat/sleutel (PEM/P12)
|
||||
certSign.tags=authenticeren,PEM,P12,officieel,versleutelen
|
||||
|
||||
home.pageLayout.title=Multi-pagina indeling
|
||||
home.pageLayout.desc=Voeg meerdere pagina''s van een PDF-document samen op één pagina
|
||||
pageLayout.tags=samenvoegen,composiet,enkel-zicht,organiseren
|
||||
|
||||
home.scalePages.title=Aanpassen paginaformaat/schaal
|
||||
home.scalePages.desc=Wijzig de grootte/schaal van een pagina en/of de inhoud ervan.
|
||||
scalePages.tags=resize,aanpassen,dimensie,aanpassen
|
||||
|
||||
home.pipeline.title=Pijplijn (Geavanceerd)
|
||||
home.pipeline.desc=Voer meerdere acties uit op PDF''s door pipelinescripts te definiëren
|
||||
pipeline.tags=automatiseren,volgorde,gescrript,batch-verwerking
|
||||
|
||||
home.add-page-numbers.title=Paginanummers toevoegen
|
||||
home.add-page-numbers.desc=Voeg paginanummers toe binnen het volledige document op een vastgestelde locatie
|
||||
add-page-numbers.tags=pagineren,labelen,organiseren,indexeren
|
||||
|
||||
home.auto-rename.title=Automatisch hernoemen PDF-bestand
|
||||
home.auto-rename.desc=Hernoemt automatisch een PDF-bestand op basis van de gedetecteerde header
|
||||
auto-rename.tags=auto-detecteren,op-header-gebaseerd,organiseren,herlabelen
|
||||
|
||||
home.adjust-contrast.title=Kleuren/Contrast aanpassen
|
||||
home.adjust-contrast.desc=Pas Contrast, Verzadiging en Helderheid van een PDF aan
|
||||
adjust-contrast.tags=kleur-correctie,afstemmen,aanpassen,verbeteren
|
||||
|
||||
home.crop.title=PDF bijsnijden
|
||||
home.crop.desc=Snijd een PDF bij om de grootte te verkleinen (behoudt tekst!)
|
||||
crop.tags=trimmen,verkleinen,bewerken,vorm
|
||||
|
||||
home.autoSplitPDF.title=Automatisch splitsen pagina''s
|
||||
home.autoSplitPDF.desc=Automatisch splitsen van gescande PDF met fysieke gescande paginasplitter QR-code
|
||||
autoSplitPDF.tags=QR-gebaseerd,scheiden,scan-segment,organiseren
|
||||
|
||||
home.sanitizePdf.title=Opschonen
|
||||
home.sanitizePdf.desc=Verwijder scripts en andere elementen uit PDF-bestanden
|
||||
sanitizePdf.tags=schoonmaken,veilig,veilig,bedreigingen verwijderen
|
||||
|
||||
home.URLToPDF.title=URL/Website naar PDF
|
||||
home.URLToPDF.desc=Zet http(s)URL om naar PDF
|
||||
URLToPDF.tags=web-capture,pagina opslaan,web-naar-doc,archief
|
||||
|
||||
home.HTMLToPDF.title=HTML naar PDF
|
||||
home.HTMLToPDF.desc=Zet HTML-bestand of zip om naar PDF
|
||||
HTMLToPDF.tags=markup,web-inhoud,transformatie,omzetten
|
||||
|
||||
|
||||
home.MarkdownToPDF.title=Markdown naar PDF
|
||||
home.MarkdownToPDF.desc=Zet Markdown-bestand om naar PDF
|
||||
MarkdownToPDF.tags=markup,web-inhoud,transformatie,omzetten
|
||||
|
||||
|
||||
home.getPdfInfo.title=Haal ALLE informatie op over PDF
|
||||
home.getPdfInfo.desc=Haalt alle mogelijke informatie op van PDF''s
|
||||
getPdfInfo.tags=informatie,data,statistieken
|
||||
|
||||
|
||||
home.extractPage.title=Pagina(''s) extraheren
|
||||
home.extractPage.desc=Extraheert geselecteerde pagina''s uit PDF
|
||||
extractPage.tags=extraheren
|
||||
|
||||
|
||||
home.PdfToSinglePage.title=PDF naar één grote pagina
|
||||
home.PdfToSinglePage.desc=Voegt alle PDF-pagina''s samen tot één grote pagina
|
||||
PdfToSinglePage.tags=één pagina
|
||||
|
||||
|
||||
home.showJS.title=Toon Javascript
|
||||
home.showJS.desc=Zoekt en toont ieder script dat in een PDF is geïnjecteerd
|
||||
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=Toon Javascript
|
||||
showJS.header=Toon Javascript
|
||||
showJS.downloadJS=Download Javascript
|
||||
showJS.submit=Toon
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
pdfToSinglePage.title=PDF naar enkele pagina
|
||||
pdfToSinglePage.header=PDF naar enkele pagina
|
||||
pdfToSinglePage.submit=Converteren naar enkele pagina
|
||||
|
||||
|
||||
#pageExtracter
|
||||
pageExtracter.title=Pagina''s extraheren
|
||||
pageExtracter.header=Pagina''s extraheren
|
||||
pageExtracter.submit=Extraheren
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
getPdfInfo.title=Informatie over PDF ophalen
|
||||
getPdfInfo.header=Informatie over PDF ophalen
|
||||
getPdfInfo.submit=Haal informatie op
|
||||
getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
MarkdownToPDF.title=Markdown naar PDF
|
||||
MarkdownToPDF.header=Markdown naar PDF
|
||||
MarkdownToPDF.submit=Converteren
|
||||
MarkdownToPDF.help=in ontwikkeling
|
||||
MarkdownToPDF.credit=Gebruikt WeasyPrint
|
||||
|
||||
|
||||
|
||||
#url-to-pdf
|
||||
URLToPDF.title=URL naar PDF
|
||||
URLToPDF.header=URL naar PDF
|
||||
URLToPDF.submit=Converteren
|
||||
URLToPDF.credit=Gebruikt WeasyPrint
|
||||
|
||||
|
||||
#html-to-pdf
|
||||
HTMLToPDF.title=HTML naar PDF
|
||||
HTMLToPDF.header=HTML naar PDF
|
||||
HTMLToPDF.help=Accepteert HTML-bestanden en ZIP''s die html/css/afbeeldingen etc. bevatten
|
||||
HTMLToPDF.submit=Converteren
|
||||
HTMLToPDF.credit=Gebruikt WeasyPrint
|
||||
|
||||
|
||||
#sanitizePDF
|
||||
sanitizePDF.title=PDF opschonen
|
||||
sanitizePDF.header=Een PDF-bestand opschonen
|
||||
sanitizePDF.selectText.1=Verwijder Javascript-acties
|
||||
sanitizePDF.selectText.2=Verwijder ingebedde bestanden
|
||||
sanitizePDF.selectText.3=Verwijder metadata
|
||||
sanitizePDF.selectText.4=Verwijder links
|
||||
sanitizePDF.selectText.5=Verwijder lettertypen
|
||||
sanitizePDF.submit=PDF opschonen
|
||||
|
||||
|
||||
#addPageNumbers
|
||||
addPageNumbers.title=Paginanummers toevoegen
|
||||
addPageNumbers.header=Paginanummers toevoegen
|
||||
addPageNumbers.selectText.1=Selecteer PDF-bestand:
|
||||
addPageNumbers.selectText.2=Margegrootte
|
||||
addPageNumbers.selectText.3=Positie
|
||||
addPageNumbers.selectText.4=Startnummer
|
||||
addPageNumbers.selectText.5=Pagina''s om te nummeren
|
||||
addPageNumbers.selectText.6=Aangepaste tekst
|
||||
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=Paginanummers toevoegen
|
||||
|
||||
|
||||
#auto-rename
|
||||
auto-rename.title=Automatisch hernoemen
|
||||
auto-rename.header=PDF automatisch hernoemen
|
||||
auto-rename.submit=Automatisch hernoemen
|
||||
|
||||
|
||||
#adjustContrast
|
||||
adjustContrast.title=Contrast aanpassen
|
||||
adjustContrast.header=Contrast aanpassen
|
||||
adjustContrast.contrast=Contrast:
|
||||
adjustContrast.brightness=Helderheid:
|
||||
adjustContrast.saturation=Verzadiging:
|
||||
adjustContrast.download=Downloaden
|
||||
|
||||
|
||||
#crop
|
||||
crop.title=Bijwerken
|
||||
crop.header=Afbeelding bijwerken
|
||||
crop.submit=Indienen
|
||||
|
||||
|
||||
#autoSplitPDF
|
||||
autoSplitPDF.title=PDF automatisch splitsen
|
||||
autoSplitPDF.header=PDF automatisch splitsen
|
||||
autoSplitPDF.description=Print, Voeg in, Scan, upload, en laat ons je documenten automatisch scheiden. Geen handmatig sorteerwerk nodig.
|
||||
autoSplitPDF.selectText.1=Print enkele scheidingsbladen van hieronder (Zwart-wit is prima).
|
||||
autoSplitPDF.selectText.2=Scan al je documenten tegelijk door het scheidingsblad ertussen te plaatsen.
|
||||
autoSplitPDF.selectText.3=Upload het enkele grote gescande PDF-bestand en laat Stirling PDF de rest afhandelen.
|
||||
autoSplitPDF.selectText.4=Scheidingspagina''s worden automatisch gedetecteerd en verwijderd, wat een net einddocument garandeert.
|
||||
autoSplitPDF.formPrompt=Dien PDF in met Stirling-PDF Pagina-scheiders:
|
||||
autoSplitPDF.duplexMode=Duplex Modus (voor- en achterkant scannen)
|
||||
autoSplitPDF.dividerDownload1=Download 'Auto Splitter Divider (minimal).pdf'
|
||||
autoSplitPDF.dividerDownload2=Download 'Auto Splitter Divider (with instructions).pdf'
|
||||
autoSplitPDF.submit=Indienen
|
||||
|
||||
|
||||
#pipeline
|
||||
pipeline.title=Pijplijn
|
||||
|
||||
|
||||
#pageLayout
|
||||
pageLayout.title=Meerdere pagina indeling
|
||||
pageLayout.header=Meerdere pagina indeling
|
||||
pageLayout.pagesPerSheet=Pagina''s per vel:
|
||||
pageLayout.submit=Indienen
|
||||
|
||||
|
||||
#scalePages
|
||||
scalePages.title=Pagina-schaal aanpassen
|
||||
scalePages.header=Pagina-schaal aanpassen
|
||||
scalePages.pageSize=Grootte van een pagina van het document.
|
||||
scalePages.scaleFactor=Zoomniveau (uitsnede) van een pagina.
|
||||
scalePages.submit=Indienen
|
||||
|
||||
|
||||
#certSign
|
||||
certSign.title=Certificaat ondertekening
|
||||
certSign.header=Onderteken een PDF met je certificaat (in ontwikkeling)
|
||||
certSign.selectPDF=Selecteer een PDF-bestand voor ondertekening:
|
||||
certSign.selectKey=Selecteer je privésleutelbestand (PKCS#8 formaat, kan .pem of .der zijn):
|
||||
certSign.selectCert=Selecteer je certificaatbestand (X.509 formaat, kan .pem of .der zijn):
|
||||
certSign.selectP12=Selecteer je PKCS#12 Sleutelopslagbestand (.p12 of .pfx) (Optioneel, indien verstrekt, moet het je privésleutel en certificaat bevatten):
|
||||
certSign.certType=Certificaattype
|
||||
certSign.password=Voer je sleutelopslag of privésleutel wachtwoord in (indien van toepassing):
|
||||
certSign.showSig=Toon handtekening
|
||||
certSign.reason=Reden
|
||||
certSign.location=Locatie
|
||||
certSign.name=Naam
|
||||
certSign.submit=PDF ondertekenen
|
||||
|
||||
|
||||
#removeBlanks
|
||||
removeBlanks.title=Verwijder blanco''s
|
||||
removeBlanks.header=Verwijder lege pagina''s
|
||||
removeBlanks.threshold=Pixel witheid drempel:
|
||||
removeBlanks.thresholdDesc=Drempel voor het bepalen hoe wit een witte pixel moet zijn om als ''Wit'' te worden geclassificeerd. 0 = Zwart, 255 zuiver wit.
|
||||
removeBlanks.whitePercent=Wit percentage (%):
|
||||
removeBlanks.whitePercentDesc=Percentage van de pagina dat ''witte'' pixels moet zijn om verwijderd te worden
|
||||
removeBlanks.submit=Blanco''s verwijderen
|
||||
|
||||
|
||||
#compare
|
||||
compare.title=Vergelijken
|
||||
compare.header=PDF''s vergelijken
|
||||
compare.document.1=Document 1
|
||||
compare.document.2=Document 2
|
||||
compare.submit=Vergelijken
|
||||
|
||||
|
||||
#sign
|
||||
sign.title=Ondertekenen
|
||||
sign.header=PDF''s ondertekenen
|
||||
sign.upload=Upload afbeelding
|
||||
sign.draw=Handtekening tekenen
|
||||
sign.text=Tekstinvoer
|
||||
sign.clear=Wissen
|
||||
sign.add=Toevoegen
|
||||
|
||||
|
||||
#repair
|
||||
repair.title=Repareren
|
||||
repair.header=PDF''s repareren
|
||||
repair.submit=Repareren
|
||||
|
||||
|
||||
#flatten
|
||||
flatten.title=Afvlakken
|
||||
flatten.header=PDF''s afvlakken
|
||||
flatten.submit=Afvlakken
|
||||
|
||||
|
||||
#ScannerImageSplit
|
||||
ScannerImageSplit.selectText.1=Hoek drempel:
|
||||
ScannerImageSplit.selectText.2=Stelt de minimale absolute hoek in die nodig is om de afbeelding te roteren (standaard: 10).
|
||||
ScannerImageSplit.selectText.3=Tolerantie:
|
||||
ScannerImageSplit.selectText.4=Bepaalt het bereik van kleurvariatie rond de geschatte achtergrondkleur (standaard: 30).
|
||||
ScannerImageSplit.selectText.5=Minimum oppervlakte:
|
||||
ScannerImageSplit.selectText.6=Stelt de minimale oppervlakte drempel in voor een foto (standaard: 10000).
|
||||
ScannerImageSplit.selectText.7=Minimum contour oppervlakte:
|
||||
ScannerImageSplit.selectText.8=Stelt de minimale contour oppervlakte drempel in voor een foto
|
||||
ScannerImageSplit.selectText.9=Randgrootte:
|
||||
ScannerImageSplit.selectText.10=Stelt de grootte van de toegevoegde en verwijderde rand in om witte randen in de uitvoer te voorkomen (standaard: 1).
|
||||
|
||||
|
||||
#OCR
|
||||
ocr.title=OCR / Scan opruimen
|
||||
ocr.header=Scans opruimen / OCR (Optical Character Recognition)
|
||||
ocr.selectText.1=Selecteer talen die binnen de PDF gedetecteerd moeten worden (De vermelde zijn de momenteel gedetecteerde):
|
||||
ocr.selectText.2=Produceer tekstbestand met OCR-tekst naast de OCR''d PDF
|
||||
ocr.selectText.3=Corrigeer pagina''s die onder een scheve hoek zijn gescand door ze terug te draaien
|
||||
ocr.selectText.4=Maak de pagina schoon, zodat het minder waarschijnlijk is dat OCR tekst in achtergrondruis vindt. (Geen uitvoerverandering)
|
||||
ocr.selectText.5=Maak de pagina schoon zodat OCR waarschijnlijk geen tekst in achtergrondruis vindt, behoudt opruiming in uitvoer.
|
||||
ocr.selectText.6=Negeert pagina''s met interactieve tekst, OCR''s alleen pagina''s die afbeeldingen zijn
|
||||
ocr.selectText.7=Forceer OCR, zal elke pagina OCR''en en alle originele tekstelementen verwijderen
|
||||
ocr.selectText.8=Normaal (Zal een fout geven als de PDF tekst bevat)
|
||||
ocr.selectText.9=Aanvullende instellingen
|
||||
ocr.selectText.10=OCR-modus
|
||||
ocr.selectText.11=Verwijder afbeeldingen na OCR (Verwijdert ALLE afbeeldingen, alleen nuttig als onderdeel van conversiestap)
|
||||
ocr.selectText.12=Render Type (Geavanceerd)
|
||||
ocr.help=Lees deze documentatie over hoe dit te gebruiken voor andere talen en/of gebruik buiten docker
|
||||
ocr.credit=Deze dienst maakt gebruik van OCRmyPDF en Tesseract voor OCR.
|
||||
ocr.submit=Verwerk PDF met OCR
|
||||
|
||||
|
||||
#extractImages
|
||||
extractImages.title=Afbeeldingen extraheren
|
||||
extractImages.header=Afbeeldingen extraheren
|
||||
extractImages.selectText=Selecteer het beeldformaat voor geëxtraheerde afbeeldingen
|
||||
extractImages.submit=Extraheer
|
||||
|
||||
|
||||
#File to PDF
|
||||
fileToPDF.title=Bestand naar PDF
|
||||
fileToPDF.header=Zet elk bestand om naar PDF
|
||||
fileToPDF.credit=Deze service gebruikt LibreOffice en Unoconv voor bestandsconversie.
|
||||
fileToPDF.supportedFileTypes=Ondersteunde bestandstypen zijn hieronder opgenomen, maar raadpleeg voor een volledige lijst met ondersteunde formaten de LibreOffice-documentatie
|
||||
fileToPDF.submit=Omzetten naar PDF
|
||||
|
||||
|
||||
#compress
|
||||
compress.title=Comprimeren
|
||||
compress.header=PDF comprimeren
|
||||
compress.credit=Deze functie gebruikt Ghostscript voor PDF Compressie/Optimalisatie.
|
||||
compress.selectText.1=Handmatige modus - Van 1 tot 4
|
||||
compress.selectText.2=Optimalisatieniveau:
|
||||
compress.selectText.3=4 (Verschrikkelijk voor tekstafbeeldingen)
|
||||
compress.selectText.4=Automatische modus - Past kwaliteit automatisch aan om PDF naar exacte grootte te krijgen
|
||||
compress.selectText.5=Verwachte PDF-grootte (bijv. 25MB, 10.8MB, 25KB)
|
||||
compress.submit=Comprimeren
|
||||
|
||||
|
||||
#Add image
|
||||
addImage.title=Afbeelding toevoegen
|
||||
addImage.header=Afbeelding aan PDF toevoegen
|
||||
addImage.everyPage=Elke pagina?
|
||||
addImage.upload=Afbeelding toevoegen
|
||||
addImage.submit=Afbeelding toevoegen
|
||||
|
||||
|
||||
#merge
|
||||
merge.title=Samenvoegen
|
||||
merge.header=Meerdere PDF''s samenvoegen (2+)
|
||||
merge.sortByName=Sorteer op naam
|
||||
merge.sortByDate=Sorteer op datum
|
||||
merge.submit=Samenvoegen
|
||||
|
||||
|
||||
#pdfOrganiser
|
||||
pdfOrganiser.title=Pagina organisator
|
||||
pdfOrganiser.header=PDF pagina organisator
|
||||
pdfOrganiser.submit=Pagina''s herschikken
|
||||
|
||||
|
||||
#multiTool
|
||||
multiTool.title=PDF Multitool
|
||||
multiTool.header=PDF Multitool
|
||||
|
||||
|
||||
#pageRemover
|
||||
pageRemover.title=Pagina verwijderaar
|
||||
pageRemover.header=PDF pagina verwijderaar
|
||||
pageRemover.pagesToDelete=Te verwijderen pagina''s (Voer een door komma''s gescheiden lijst met paginanummers in):
|
||||
pageRemover.submit=Pagina''s verwijderen
|
||||
|
||||
|
||||
#rotate
|
||||
rotate.title=PDF roteren
|
||||
rotate.header=PDF roteren
|
||||
rotate.selectAngle=Selecteer rotatiehoek (in veelvouden van 90 graden):
|
||||
rotate.submit=Roteren
|
||||
|
||||
|
||||
#merge
|
||||
split.title=PDF splitsen
|
||||
split.header=PDF splitsen
|
||||
split.desc.1=De nummers die je kiest zijn de paginanummers waarop je een splitsing wilt uitvoeren
|
||||
split.desc.2=Als zodanig selecteren van 1,3,7-8 zou een 10 pagina''s tellend document splitsen in 6 aparte PDF''s met:
|
||||
split.desc.3=Document #1: Pagina 1
|
||||
split.desc.4=Document #2: Pagina 2 en 3
|
||||
split.desc.5=Document #3: Pagina 4, 5 en 6
|
||||
split.desc.6=Document #4: Pagina 7
|
||||
split.desc.7=Document #5: Pagina 8
|
||||
split.desc.8=Document #6: Pagina 9 en 10
|
||||
split.splitPages=Voer pagina''s in om op te splitsen:
|
||||
split.submit=Splitsen
|
||||
|
||||
|
||||
#merge
|
||||
imageToPDF.title=Afbeelding naar PDF
|
||||
imageToPDF.header=Afbeelding naar PDF
|
||||
imageToPDF.submit=Omzetten
|
||||
imageToPDF.selectText.1=Uitrekken om te passen
|
||||
imageToPDF.selectText.2=PDF automatisch draaien
|
||||
imageToPDF.selectText.3=Meervoudige bestandslogica (Alleen ingeschakeld bij werken met meerdere afbeeldingen)
|
||||
imageToPDF.selectText.4=Voeg samen in één PDF
|
||||
imageToPDF.selectText.5=Zet om naar afzonderlijke PDF''s
|
||||
|
||||
|
||||
#pdfToImage
|
||||
pdfToImage.title=PDF naar afbeelding
|
||||
pdfToImage.header=PDF naar afbeelding
|
||||
pdfToImage.selectText=Afbeeldingsformaat
|
||||
pdfToImage.singleOrMultiple=Resultaattype van pagina naar afbeelding
|
||||
pdfToImage.single=Eén grote afbeelding die alle pagina''s combineert
|
||||
pdfToImage.multi=Meerdere afbeeldingen, één afbeelding per pagina
|
||||
pdfToImage.colorType=Kleurtype
|
||||
pdfToImage.color=Kleur
|
||||
pdfToImage.grey=Grijstinten
|
||||
pdfToImage.blackwhite=Zwart en wit (kan data verliezen!)
|
||||
pdfToImage.submit=Omzetten
|
||||
|
||||
|
||||
#addPassword
|
||||
addPassword.title=Wachtwoord toevoegen
|
||||
addPassword.header=Wachtwoord toevoegen (Versleutelen)
|
||||
addPassword.selectText.1=Selecteer PDF om te versleutelen
|
||||
addPassword.selectText.2=Gebruikerswachtwoord
|
||||
addPassword.selectText.3=Versleutelingssleutellengte
|
||||
addPassword.selectText.4=Hogere waarden zijn sterker, maar lagere waarden hebben een betere compatibiliteit.
|
||||
addPassword.selectText.5=In te stellen rechten (Aanbevolen om te gebruiken samen met eigenaarswachtwoord)
|
||||
addPassword.selectText.6=Voorkomen van documentassemblage
|
||||
addPassword.selectText.7=Voorkomen van inhoudsextractie
|
||||
addPassword.selectText.8=Voorkomen van extractie voor toegankelijkheid
|
||||
addPassword.selectText.9=Voorkomen van invullen van formulier
|
||||
addPassword.selectText.10=Voorkomen van wijziging
|
||||
addPassword.selectText.11=Voorkomen van annotatiewijziging
|
||||
addPassword.selectText.12=Voorkomen van afdrukken
|
||||
addPassword.selectText.13=Voorkomen van afdrukken in verschillende formaten
|
||||
addPassword.selectText.14=Eigenaarswachtwoord
|
||||
addPassword.selectText.15=Beperkt wat gedaan kan worden met het document nadat het is geopend (Niet ondersteund door alle lezers)
|
||||
addPassword.selectText.16=Beperkt het openen van het document zelf
|
||||
addPassword.submit=Versleutelen
|
||||
|
||||
|
||||
#watermark
|
||||
watermark.title=Watermerk toevoegen
|
||||
watermark.header=Watermerk toevoegen
|
||||
watermark.selectText.1=Selecteer PDF om watermerk toe te voegen:
|
||||
watermark.selectText.2=Watermerk tekst:
|
||||
watermark.selectText.3=Tekengrootte:
|
||||
watermark.selectText.4=Rotatie (0-360):
|
||||
watermark.selectText.5=breedteSpacer (Ruimte tussen elk watermerk horizontaal):
|
||||
watermark.selectText.6=hoogteSpacer (Ruimte tussen elk watermerk verticaal):
|
||||
watermark.selectText.7=Transparantie (0% - 100%):
|
||||
watermark.selectText.8=Type watermerk:
|
||||
watermark.selectText.9=Watermerk afbeelding:
|
||||
watermark.submit=Watermerk toevoegen
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Rechten wijzigen
|
||||
permissions.header=Rechten wijzigen
|
||||
permissions.warning=Let op: om deze rechten onveranderlijk te maken, wordt aanbevolen om ze met een wachtwoord in te stellen via de add-password pagina.
|
||||
permissions.selectText.1=Selecteer PDF om rechten te wijzigen
|
||||
permissions.selectText.2=In te stellen rechten
|
||||
permissions.selectText.3=Voorkom samenvoegen van document
|
||||
permissions.selectText.4=Voorkom inhoudsextractie
|
||||
permissions.selectText.5=Voorkom extractie voor toegankelijkheid
|
||||
permissions.selectText.6=Voorkom invullen van formulier
|
||||
permissions.selectText.7=Voorkom wijziging
|
||||
permissions.selectText.8=Voorkom annotatie wijziging
|
||||
permissions.selectText.9=Voorkom afdrukken
|
||||
permissions.selectText.10=Voorkom afdrukken in verschillende formaten
|
||||
permissions.submit=Wijzigen
|
||||
|
||||
|
||||
#remove password
|
||||
removePassword.title=Wachtwoord verwijderen
|
||||
removePassword.header=Wachtwoord verwijderen (Decrypteren)
|
||||
removePassword.selectText.1=Selecteer PDF om te decrypteren
|
||||
removePassword.selectText.2=Wachtwoord
|
||||
removePassword.submit=Verwijderen
|
||||
|
||||
|
||||
#changeMetadata
|
||||
changeMetadata.title=Titel:
|
||||
changeMetadata.header=Metadata wijzigen
|
||||
changeMetadata.selectText.1=Pas de variabelen aan die je wilt wijzigen
|
||||
changeMetadata.selectText.2=Verwijder alle metadata
|
||||
changeMetadata.selectText.3=Toon aangepaste metadata:
|
||||
changeMetadata.author=Auteur:
|
||||
changeMetadata.creationDate=Aanmaakdatum (yyyy/MM/dd HH:mm:ss):
|
||||
changeMetadata.creator=Maker:
|
||||
changeMetadata.keywords=Trefwoorden:
|
||||
changeMetadata.modDate=Wijzigingsdatum (yyyy/MM/dd HH:mm:ss):
|
||||
changeMetadata.producer=Producent:
|
||||
changeMetadata.subject=Onderwerp:
|
||||
changeMetadata.title=Titel:
|
||||
changeMetadata.trapped=Vastgezet:
|
||||
changeMetadata.selectText.4=Overige metadata:
|
||||
changeMetadata.selectText.5=Voeg aangepaste metadata-invoer toe
|
||||
changeMetadata.submit=Wijzigen
|
||||
|
||||
|
||||
#xlsToPdf
|
||||
xlsToPdf.title=Excel naar PDF
|
||||
xlsToPdf.header=Excel naar PDF
|
||||
xlsToPdf.selectText.1=Selecteer XLS of XLSX Excel-blad om te converteren
|
||||
xlsToPdf.convert=Converteren
|
||||
|
||||
|
||||
#pdfToPDFA
|
||||
pdfToPDFA.title=PDF naar PDF/A
|
||||
pdfToPDFA.header=PDF naar PDF/A
|
||||
pdfToPDFA.credit=Deze service gebruikt OCRmyPDF voor PDF/A-conversie
|
||||
pdfToPDFA.submit=Converteren
|
||||
|
||||
|
||||
#PDFToWord
|
||||
PDFToWord.title=PDF naar Word
|
||||
PDFToWord.header=PDF naar Word
|
||||
PDFToWord.selectText.1=Uitvoerbestandsformaat
|
||||
PDFToWord.credit=Deze service gebruikt LibreOffice voor bestandsconversie.
|
||||
PDFToWord.submit=Converteren
|
||||
|
||||
|
||||
#PDFToPresentation
|
||||
PDFToPresentation.title=PDF naar Presentatie
|
||||
PDFToPresentation.header=PDF naar Presentatie
|
||||
PDFToPresentation.selectText.1=Uitvoerbestandsformaat
|
||||
PDFToPresentation.credit=Deze service gebruikt LibreOffice voor bestandsconversie.
|
||||
PDFToPresentation.submit=Converteren
|
||||
|
||||
|
||||
#PDFToText
|
||||
PDFToText.title=PDF naar RTF (Tekst)
|
||||
PDFToText.header=PDF naar RTF (Tekst)
|
||||
PDFToText.selectText.1=Uitvoerbestandsformaat
|
||||
PDFToText.credit=Deze service gebruikt LibreOffice voor bestandsconversie.
|
||||
PDFToText.submit=Converteren
|
||||
|
||||
|
||||
#PDFToHTML
|
||||
PDFToHTML.title=PDF naar HTML
|
||||
PDFToHTML.header=PDF naar HTML
|
||||
PDFToHTML.credit=Deze service gebruikt LibreOffice voor bestandsconversie.
|
||||
PDFToHTML.submit=Converteren
|
||||
|
||||
|
||||
#PDFToXML
|
||||
PDFToXML.title=PDF naar XML
|
||||
PDFToXML.header=PDF naar XML
|
||||
PDFToXML.credit=Deze service gebruikt LibreOffice voor bestandsconversie.
|
||||
PDFToXML.submit=Converteren
|
||||
@@ -31,7 +31,11 @@ sizes.medium=Medium
|
||||
sizes.large=Large
|
||||
sizes.x-large=X-Large
|
||||
error.pdfPassword=Dokument PDF jest zabezpieczony hasłem, musisz podać prawidłowe hasło.
|
||||
|
||||
delete=Delete
|
||||
username=Username
|
||||
password=Password
|
||||
welcome=Welcome
|
||||
=Property
|
||||
|
||||
#############
|
||||
# NAVBAR #
|
||||
@@ -54,6 +58,41 @@ settings.downloadOption.1=Otwórz w tym samym oknie
|
||||
settings.downloadOption.2=Otwórz w nowym oknie
|
||||
settings.downloadOption.3=Pobierz plik
|
||||
settings.zipThreshold=Spakuj pliki, gdy liczba pobranych plików przekroczy
|
||||
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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Dodaj obraz
|
||||
#merge
|
||||
merge.title=Połącz
|
||||
merge.header=Połącz wiele dokumentów PDF (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Połącz
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Obrót (0-360):
|
||||
watermark.selectText.5=Odstęp w poziomie (odstęp między każdym znakiem wodnym w poziomie):
|
||||
watermark.selectText.6=Odstęp w pionie (odstęp między każdym znakiem wodnym w pionie):
|
||||
watermark.selectText.7=Nieprzezroczystość (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.submit=Dodaj znak wodny
|
||||
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=Usuń znak wodny
|
||||
remove-watermark.header=Usuń znak wodny
|
||||
remove-watermark.selectText.1=Wybierz dokument PDF, aby usunąć znak wodny z:
|
||||
remove-watermark.selectText.2=Treść zanku wodnego:
|
||||
remove-watermark.submit=Usuń znak wodny
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Zmień uprawnienia
|
||||
permissions.header=Zmień uprawnienia
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ settings.downloadOption.1=Deschide în aceeași fereastră
|
||||
settings.downloadOption.2=Deschide într-o fereastră nouă
|
||||
settings.downloadOption.3=Descarcă fișierul
|
||||
settings.zipThreshold=Împachetează fișierele când numărul de fișiere descărcate depășește
|
||||
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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Adăugare imagine
|
||||
#merge
|
||||
merge.title=Unire
|
||||
merge.header=Unirea mai multor PDF-uri (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Unire
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Rotire (0-360):
|
||||
watermark.selectText.5=widthSpacer (Spațiu între fiecare filigran pe orizontală):
|
||||
watermark.selectText.6=heightSpacer (Spațiu între fiecare filigran pe verticală):
|
||||
watermark.selectText.7=Opacitate (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.submit=Adăugați Filigran
|
||||
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=Eliminați Filigran
|
||||
remove-watermark.header=Eliminați Filigran
|
||||
remove-watermark.selectText.1=Selectați PDF-ul de la care să eliminați filigranul:
|
||||
remove-watermark.selectText.2=Textul Filigranului:
|
||||
remove-watermark.submit=Eliminați Filigran
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Schimbați Permisiunile
|
||||
permissions.header=Schimbați Permisiunile
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ settings.downloadOption.1=Открыть в том же окне
|
||||
settings.downloadOption.2=Открыть в новом окне
|
||||
settings.downloadOption.3=Загрузить файл
|
||||
settings.zipThreshold=Zip-файлы, когда количество загруженных файлов превышает
|
||||
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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Добавить изображение
|
||||
#merge
|
||||
merge.title=Объединить
|
||||
merge.header=Объединение нескольких PDF-файлов (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Объединить
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Поворот (0-360):
|
||||
watermark.selectText.5=widthSpacer (пробел между каждым водяным знаком по горизонтали):
|
||||
watermark.selectText.6=heightSpacer (пробел между каждым водяным знаком по вертикали):
|
||||
watermark.selectText.7=Непрозрачность (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.submit=Добавить водяной знак
|
||||
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=Удалить водяной знак
|
||||
remove-watermark.header=Удалить водяной знак
|
||||
remove-watermark.selectText.1=Выберите PDF, чтобы удалить водяной знак из:
|
||||
remove-watermark.selectText.2=Текст водяного знака:
|
||||
remove-watermark.submit=Удалить водяной знак
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Изменить разрешения
|
||||
permissions.header=Изменить разрешения
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ settings.downloadOption.1=Öppnas i samma fönster
|
||||
settings.downloadOption.2=Öppna i nytt fönster
|
||||
settings.downloadOption.3=Ladda ner fil
|
||||
settings.zipThreshold=Zip-filer när antalet nedladdade filer överskrider
|
||||
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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=Lägg till bild
|
||||
#merge
|
||||
merge.title=Sammanfoga
|
||||
merge.header=Slå samman flera PDF-filer (2+)
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=Slå samman
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=Rotation (0-360):
|
||||
watermark.selectText.5=widthSpacer (mellanrum mellan varje vattenstämpel horisontellt):
|
||||
watermark.selectText.6=heightSpacer (mellanrum mellan varje vattenstämpel vertikalt):
|
||||
watermark.selectText.7=Opacitet (0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.submit=Lägg till vattenstämpel
|
||||
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=Ta bort vattenstämpel
|
||||
remove-watermark.header=Ta bort vattenstämpel
|
||||
remove-watermark.selectText.1=Välj PDF för att ta bort vattenstämpel från:
|
||||
remove-watermark.selectText.2=Vattenstämpeltext:
|
||||
remove-watermark.submit=Ta bort vattenstämpel
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Ändra behörigheter
|
||||
permissions.header=Ändra behörigheter
|
||||
|
||||
@@ -31,7 +31,11 @@ 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 #
|
||||
@@ -54,6 +58,41 @@ 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 #
|
||||
@@ -236,67 +275,83 @@ home.HTMLToPDF.desc=Converts any HTML file or zip to PDF
|
||||
HTMLToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.MarkdownToPDF.title=Markdown to PDF
|
||||
home.MarkdownToPDF.desc=Converts any Markdown file to PDF
|
||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
home.extractPage.title=Extract page(s)
|
||||
home.extractPage.desc=Extracts select pages from PDF
|
||||
extractPage.tags=extract
|
||||
|
||||
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
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 #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
#pdfToSinglePage
|
||||
#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
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
pageExtracter.title=Extract Pages
|
||||
pageExtracter.header=Extract Pages
|
||||
pageExtracter.submit=Extract
|
||||
|
||||
|
||||
#getPdfInfo
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
getPdfInfo.title=Get Info on PDF
|
||||
getPdfInfo.header=Get Info on PDF
|
||||
getPdfInfo.submit=Get Info
|
||||
@@ -304,9 +359,6 @@ getPdfInfo.downloadJson=Download JSON
|
||||
|
||||
|
||||
#markdown-to-pdf
|
||||
##########################
|
||||
### TODO: Translate ###
|
||||
##########################
|
||||
MarkdownToPDF.title=Markdown To PDF
|
||||
MarkdownToPDF.header=Markdown To PDF
|
||||
MarkdownToPDF.submit=Convert
|
||||
@@ -350,6 +402,9 @@ 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
|
||||
|
||||
|
||||
@@ -535,6 +590,8 @@ addImage.submit=添加图片
|
||||
#merge
|
||||
merge.title=合并
|
||||
merge.header=合并多个PDF(2个以上)。
|
||||
merge.sortByName=Sort by name
|
||||
merge.sortByDate=Sort by date
|
||||
merge.submit=合并
|
||||
|
||||
|
||||
@@ -635,17 +692,11 @@ watermark.selectText.4=旋转(0-360):
|
||||
watermark.selectText.5=widthSpacer(水平方向上每个水印之间的空间):
|
||||
watermark.selectText.6=heightSpacer(每个水印之间的垂直空间):
|
||||
watermark.selectText.7=透明度(0% - 100%):
|
||||
watermark.selectText.8=Watermark Type:
|
||||
watermark.selectText.9=Watermark Image:
|
||||
watermark.submit=添加水印
|
||||
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=去除水印
|
||||
remove-watermark.header=去除水印
|
||||
remove-watermark.selectText.1=选择要去除水印的PDF:
|
||||
remove-watermark.selectText.2=水印文本:
|
||||
remove-watermark.submit=移除水印
|
||||
|
||||
|
||||
#Change permissions
|
||||
permissions.title=更改权限
|
||||
permissions.header=改变权限
|
||||
|
||||
31
src/main/resources/settings.yml.template
Normal file
@@ -0,0 +1,31 @@
|
||||
# Welcome to settings file
|
||||
# Remove comment marker # if on start of line to enable the configuration
|
||||
# If you want to override with environment parameter follow parameter naming SECURITY_INITIALLOGIN_USERNAME
|
||||
|
||||
security:
|
||||
enableLogin: false # set to 'true' to enable login
|
||||
initialLogin:
|
||||
username: 'username' # Specify the initial username for first boot (e.g. 'admin')
|
||||
password: 'password'# Specify the initial password for first boot (e.g. 'password123')
|
||||
csrfDisabled: true
|
||||
|
||||
system:
|
||||
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
||||
googlevisibility: false # 'true' to allow Google visibility, 'false' to disallow
|
||||
rootURIPath: / # Set the application's root URI (e.g. /pdf-app)
|
||||
customStaticFilePath: '/customFiles/static/' # Directory path for custom static files
|
||||
maxFileSize: 2000 # Set the maximum file size in MB
|
||||
connectionTimeoutMinutes: 5m
|
||||
connectionTimeoutMilliSeconds: 300000
|
||||
|
||||
#ui:
|
||||
# appName: exampleAppName # Application's visible name
|
||||
# homeDescription: I am a description # Short description or tagline shown on homepage.
|
||||
# appNameNavbar: navbarName # Name displayed on the navigation bar
|
||||
|
||||
endpoints:
|
||||
toRemove: [] # List endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
|
||||
groupsToRemove: [] # List groups to disable (e.g. ['LibreOffice'])
|
||||
|
||||
metrics:
|
||||
enabled: true # 'true' to enable metric API endpoints, 'false' to disable
|
||||
BIN
src/main/resources/static/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/main/resources/static/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
src/main/resources/static/apple-touch-icon-114x114.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
src/main/resources/static/apple-touch-icon-120x120.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
src/main/resources/static/apple-touch-icon-144x144.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/main/resources/static/apple-touch-icon-152x152.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/main/resources/static/apple-touch-icon-180x180.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/main/resources/static/apple-touch-icon-57x57.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
src/main/resources/static/apple-touch-icon-60x60.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/main/resources/static/apple-touch-icon-72x72.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
src/main/resources/static/apple-touch-icon-76x76.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |