Compare commits

..

3 Commits

Author SHA1 Message Date
Anthony Stirling
f4082e3f96 Update PasswordController.java 2024-07-07 22:51:59 +01:00
Anthony Stirling
c93a48b40d Merge branch 'main' into decrypt 2024-07-07 22:50:41 +01:00
Anthony Stirling
75e10efcbd auto decrypt, update discord, fix multi file support for some inputs 2024-07-07 22:49:21 +01:00
98 changed files with 482 additions and 7192 deletions

View File

@@ -1,5 +1,5 @@
blank_issues_enabled: true blank_issues_enabled: true
contact_links: contact_links:
- name: 💬 Discord Server - name: 💬 Discord Server
url: https://discord.gg/Cn8pWhQRxZ url: https://discord.gg/HYmhKj45pU
about: You can join our Discord server for real time discussion and support about: You can join our Discord server for real time discussion and support

View File

@@ -1,49 +1,20 @@
Translation: translation:
- changed-files: - changed-files:
- any-glob-to-any-file: 'src/main/resources/messages_*_*.properties' - any-glob-to-any-file: 'src/main/resources/messages_*_*.properties'
- any-glob-to-any-file: 'scripts/ignore_translation.toml'
Front End: Front End:
- changed-files: - changed-files:
- any-glob-to-any-file: 'src/main/resources/templates/**/*' - any-glob-to-any-file: 'src/main/resources/templates/**'
- any-glob-to-any-file: 'src/main/resources/static/**/*'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/**'
Java: java:
- changed-files: - changed-files:
- any-glob-to-any-file: 'src/main/java/**/*.java' - any-glob-to-any-file: 'src/main/java/**/*.java'
Back End: documentation:
- changed-files:
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/security/**/*'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/model/provider/**/*'
- any-glob-to-any-file: 'src/main/resources/settings.yml.template'
- any-glob-to-any-file: 'src/main/resources/banner.txt'
Security:
- changed-files:
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/security/**/*'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/model/provider/**/*'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/model/AuthenticationType.java'
API:
- changed-files:
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/MetricsController.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/**/*'
Documentation:
- changed-files: - changed-files:
- any-glob-to-any-file: '**/*.md' - any-glob-to-any-file: '**/*.md'
- any-glob-to-any-file: 'scripts/counter_translation.py'
- any-glob-to-any-file: 'scripts/ignore_translation.toml'
Docker: docker:
- changed-files: - changed-files:
- any-glob-to-any-file: 'Dockerfile' - any-glob-to-any-file: 'Dockerfile'
- any-glob-to-any-file: 'Dockerfile-*' - any-glob-to-any-file: 'Dockerfile-*'
- any-glob-to-any-file: 'exampleYmlFiles/*.yml'
Test:
- changed-files:
- any-glob-to-any-file: 'cucumber/**/*'
- any-glob-to-any-file: 'test*'

93
.github/labels.yml vendored
View File

@@ -1,93 +0,0 @@
# Labels names are important as they are used by Release Drafter to decide
# regarding where to record them in changelog or if to skip them.
#
# The repository labels will be automatically configured using this file and
# the GitHub Action https://github.com/marketplace/actions/github-labeler.
- name: "Back End"
color: "20CE6C"
description: "Issues related to back-end development"
from_name: "Back end"
- name: "Bug"
description: "Something isn't working"
color: "EB9CA6"
from_name: "bug"
- name: "dependencies"
description: "Pull requests that update a dependency file"
color: "5AA8FC"
- name: "Docker"
description: "Pull requests that update Docker code"
color: "1FCEFF"
from_name: "docker"
- name: "Documentation"
description: "Improvements or additions to documentation"
color: "35ABFF"
from_name: "documentation"
- name: "Done for next release"
color: "0CDBD1"
- name: "Done"
color: "60F13B"
- name: "duplicate"
description: "This issue or pull request already exists"
color: "CDD1D5"
- name: "enhancement"
description: "New feature or request"
color: "A0EEEE"
- name: "fix needs confirmation"
color: "60A1E7"
description: "Fix needs to be confirmed"
- name: "Front End"
color: "BBD2F1"
description: "Issues related to front-end development"
- name: "github-actions"
description: "Pull requests that update GitHub Actions code"
color: "999999"
from_name: "github_actions"
- name: "good first issue"
description: "Good for newcomers"
color: "C1B8FF"
- name: "help wanted"
description: "Extra attention is needed"
color: "00E6C4"
- name: "invalid"
description: "This doesn't seem right"
color: "E5E566"
- name: "Java"
description: "Pull requests that update Java code"
color: "FF9E1F"
from_name: "java"
- name: "Long-term Enhancement"
color: "BFDEC3"
description: "Enhancements planned for the long term"
- name: "more-info-needed"
color: "00E4F8"
description: "More information is needed"
- name: "needs investigation"
color: "B8C3A7"
description: "Issues that require further investigation"
- name: "Prioritised enhancement"
color: "4BA2EE"
description: "High-priority enhancements"
- name: "question"
description: "Further information is requested"
color: "D97EE5"
- name: "Translation"
color: "9FABF9"
from_name: "translation"
- name: "upstream"
color: "DEDEDE"
- name: "v2"
color: "FFFF00"
- name: "wontfix"
description: "This will not be worked on"
color: "FFFFFF"
- name: "Security"
color: "000000"
description: "Security-related issues or pull requests"
- name: "API"
color: "FFFF00"
description: "API-related issues or pull requests"
- name: "Test"
color: "FF9E1F"
description: "Testing-related issues or pull requests"
- name: "Stale"
color: "000000"

View File

@@ -1,5 +1,4 @@
"""check_tabulator.py""" """check_tabulator.py"""
import argparse import argparse
import sys import sys

View File

@@ -1,24 +0,0 @@
name: Manage labels
on:
schedule:
- cron: "30 20 * * *"
permissions:
contents: read
issues: write
jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
- name: Check out the repository
uses: actions/checkout@v4
- name: Run Labeler
uses: crazy-max/ghaction-github-labeler@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
yaml-file: .github/labels.yml
skip-delete: true

View File

@@ -51,7 +51,6 @@ jobs:
[1]: https://github.com/peter-evans/create-pull-request [1]: https://github.com/peter-evans/create-pull-request
draft: false draft: false
delete-branch: true delete-branch: true
labels: github-actions
sync-readme: sync-readme:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -89,4 +88,3 @@ jobs:
[1]: https://github.com/peter-evans/create-pull-request [1]: https://github.com/peter-evans/create-pull-request
draft: false draft: false
delete-branch: true delete-branch: true
labels: Documentation,Translation,github-actions

View File

@@ -29,8 +29,8 @@ jobs:
- name: Install Docker Compose - name: Install Docker Compose
run: | run: |
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo curl -SL "https://github.com/docker/compose/releases/download/v2.26.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose # sudo chmod +x /usr/local/bin/docker-compose
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4

43
.gitignore vendored
View File

@@ -1,3 +1,5 @@
### Eclipse ### ### Eclipse ###
.metadata .metadata
bin/ bin/
@@ -20,6 +22,7 @@ customFiles/
configs/ configs/
watchedFolders/ watchedFolders/
# Gradle # Gradle
.gradle .gradle
.lock .lock
@@ -116,28 +119,8 @@ watchedFolders/
*.db *.db
/build /build
# Byte-compiled / optimized / DLL files /.vscode
__pycache__/ /.idea
*.py[cod]
*.pyo
# Virtual environments
.env*
.venv*
env*/
venv*/
ENV/
env.bak/
venv.bak/
# VS Code
/.vscode/**/*
!/.vscode/settings.json
# IntelliJ IDEA
.idea/
*.iml
out/
# Ignore Mac DS_Store files # Ignore Mac DS_Store files
.DS_Store .DS_Store
@@ -145,19 +128,3 @@ out/
#cucumber #cucumber
/cucumber/reports/** /cucumber/reports/**
# Certs
*.p12
*.pem
*.crt
*.cer
*.der
*.key
*.csr
# cache
.ruff_cache
.mypy_cache
.pytest_cache
.ipynb_checkpoints

53
.vscode/settings.json vendored
View File

@@ -1,53 +0,0 @@
{
"java.compile.nullAnalysis.mode": "automatic",
"files.eol": "auto",
"java.configuration.updateBuildConfiguration": "interactive",
"black-formatter.args": ["--line-length", "127"],
"flake8.args": ["--max-line-length", "127"],
"pylint.args": ["max-line-length", "127"],
"[java]": {
"editor.tabSize": 4,
"editor.detectIndentation": false,
"editor.rulers": [127]
},
"[python]": {
"editor.tabSize": 2,
"editor.detectIndentation": false,
"editor.rulers": [127]
},
"[gradle-build]": {
"editor.tabSize": 4,
"editor.detectIndentation": false,
"editor.rulers": [127]
},
"[gradle]": {
"editor.tabSize": 4,
"editor.detectIndentation": false,
"editor.rulers": [127]
},
"[html]": {
"editor.tabSize": 2,
"editor.rulers": [127],
"files.trimFinalNewlines": false,
"files.insertFinalNewline": false
},
"[javascript]": {
"editor.tabSize": 2,
"editor.rulers": [127]
},
"[yaml]": {
"files.trimFinalNewlines": false,
"files.insertFinalNewline": false
},
"diffEditor.maxComputationTime": 0,
"editor.wordSegmenterLocales": null,
"editor.guides.bracketPairs": "active",
"editor.guides.bracketPairsHorizontal": "active",
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"editor.indentSize": "tabSize",
"editor.stickyScroll.enabled": false,
"editor.minimap.enabled": false,
"editor.formatOnSave": true
}

View File

@@ -31,7 +31,7 @@ ENV DOCKER_ENABLE_SECURITY=false \
PGID=1000 \ PGID=1000 \
UMASK=022 \ UMASK=022 \
FAT_DOCKER=true \ FAT_DOCKER=true \
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false INSTALL_BOOK_AND_ADVANCED_HTML_OPS=true
# JDK for app # JDK for app
@@ -45,6 +45,7 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
tini \ tini \
bash \ bash \
curl \ curl \
calibre@testing \
shadow \ shadow \
su-exec \ su-exec \
openssl \ openssl \

View File

@@ -2,7 +2,7 @@
<h1 align="center">Stirling-PDF</h1> <h1 align="center">Stirling-PDF</h1>
[![Docker Pulls](https://img.shields.io/docker/pulls/frooodle/s-pdf)](https://hub.docker.com/r/frooodle/s-pdf) [![Docker Pulls](https://img.shields.io/docker/pulls/frooodle/s-pdf)](https://hub.docker.com/r/frooodle/s-pdf)
[![Discord](https://img.shields.io/discord/1068636748814483718?label=Discord)](https://discord.gg/Cn8pWhQRxZ) [![Discord](https://img.shields.io/discord/1068636748814483718?label=Discord)](https://discord.gg/HYmhKj45pU)
[![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/) [![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/)
[![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf) [![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf)
[![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/donate/?hosted_button_id=MN7JPG5G6G3JL) [![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/donate/?hosted_button_id=MN7JPG5G6G3JL)
@@ -165,46 +165,42 @@ Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR
## Supported Languages ## Supported Languages
Stirling PDF currently supports 38! Stirling PDF currently supports 32!
| Language | Progress | | Language | Progress |
| ------------------------------------------- | -------------------------------------- | | ------------------------------------------- | -------------------------------------- |
| Arabic (العربية) (ar_AR) | ![45%](https://geps.dev/progress/45) |
| Basque (Euskara) (eu_ES) | ![62%](https://geps.dev/progress/62) |
| Bulgarian (Български) (bg_BG) | ![94%](https://geps.dev/progress/94) |
| Catalan (Català) (ca_CA) | ![48%](https://geps.dev/progress/48) |
| Croatian (Hrvatski) (hr_HR) | ![95%](https://geps.dev/progress/95) |
| Czech (Česky) (cs_CZ) | ![90%](https://geps.dev/progress/90) |
| Danish (Dansk) (da_DK) | ![10%](https://geps.dev/progress/10) |
| Dutch (Nederlands) (nl_NL) | ![96%](https://geps.dev/progress/96) |
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) | | English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) | | English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) | | Arabic (العربية) (ar_AR) | ![45%](https://geps.dev/progress/45) |
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) | | German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) |
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) |
| Spanish (Español) (es_ES) | ![92%](https://geps.dev/progress/92) |
| Simplified Chinese (简体中文) (zh_CN) | ![98%](https://geps.dev/progress/98) |
| Traditional Chinese (繁體中文) (zh_TW) | ![96%](https://geps.dev/progress/96) |
| Catalan (Català) (ca_CA) | ![48%](https://geps.dev/progress/48) |
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Swedish (Svenska) (sv_SE) | ![39%](https://geps.dev/progress/39) |
| Polish (Polski) (pl_PL) | ![90%](https://geps.dev/progress/90) |
| Romanian (Română) (ro_RO) | ![39%](https://geps.dev/progress/39) |
| Korean (한국어) (ko_KR) | ![84%](https://geps.dev/progress/84) |
| Portuguese Brazilian (Português) (pt_BR) | ![60%](https://geps.dev/progress/60) |
| Portuguese (Português) (pt_PT) | ![78%](https://geps.dev/progress/78) |
| Russian (Русский) (ru_RU) | ![84%](https://geps.dev/progress/84) |
| Basque (Euskara) (eu_ES) | ![62%](https://geps.dev/progress/62) |
| Japanese (日本語) (ja_JP) | ![90%](https://geps.dev/progress/90) |
| Dutch (Nederlands) (nl_NL) | ![96%](https://geps.dev/progress/96) |
| Greek (Ελληνικά) (el_GR) | ![82%](https://geps.dev/progress/82) | | Greek (Ελληνικά) (el_GR) | ![82%](https://geps.dev/progress/82) |
| Turkish (Türkçe) (tr_TR) | ![94%](https://geps.dev/progress/94) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![76%](https://geps.dev/progress/76) |
| Hindi (हिंदी) (hi_IN) | ![77%](https://geps.dev/progress/77) | | Hindi (हिंदी) (hi_IN) | ![77%](https://geps.dev/progress/77) |
| Hungarian (Magyar) (hu_HU) | ![76%](https://geps.dev/progress/76) | | Hungarian (Magyar) (hu_HU) | ![76%](https://geps.dev/progress/76) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![76%](https://geps.dev/progress/76) | | Bulgarian (Български) (bg_BG) | ![94%](https://geps.dev/progress/94) |
| Irish (Gaeilge) (ga_IE) | ![99%](https://geps.dev/progress/99) |
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Japanese (日本語) (ja_JP) | ![90%](https://geps.dev/progress/90) |
| Korean (한국어) (ko_KR) | ![84%](https://geps.dev/progress/84) |
| Norwegian (Norsk) (no_NB) | ![96%](https://geps.dev/progress/96) |
| Polish (Polski) (pl_PL) | ![90%](https://geps.dev/progress/90) |
| Portuguese (Português) (pt_PT) | ![78%](https://geps.dev/progress/78) |
| Portuguese Brazilian (Português) (pt_BR) | ![60%](https://geps.dev/progress/60) |
| Romanian (Română) (ro_RO) | ![39%](https://geps.dev/progress/39) |
| Russian (Русский) (ru_RU) | ![84%](https://geps.dev/progress/84) |
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![78%](https://geps.dev/progress/78) | | Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![78%](https://geps.dev/progress/78) |
| Simplified Chinese (简体中文) (zh_CN) | ![99%](https://geps.dev/progress/99) |
| Slovakian (Slovensky) (sk_SK) | ![92%](https://geps.dev/progress/92) |
| Spanish (Español) (es_ES) | ![98%](https://geps.dev/progress/98) |
| Swedish (Svenska) (sv_SE) | ![39%](https://geps.dev/progress/39) |
| Thai (ไทย) (th_TH) | ![100%](https://geps.dev/progress/100) |
| Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) |
| Turkish (Türkçe) (tr_TR) | ![99%](https://geps.dev/progress/99) |
| Ukrainian (Українська) (uk_UA) | ![90%](https://geps.dev/progress/90) | | Ukrainian (Українська) (uk_UA) | ![90%](https://geps.dev/progress/90) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![99%](https://geps.dev/progress/99) | | Slovakian (Slovensky) (sk_SK) | ![92%](https://geps.dev/progress/92) |
| Czech (Česky) (cs_CZ) | ![90%](https://geps.dev/progress/90) |
| Croatian (Hrvatski) (hr_HR) | ![95%](https://geps.dev/progress/95) |
| Norwegian (Norsk) (no_NB) | ![96%](https://geps.dev/progress/96) |
## Contributing (creating issues, translations, fixing bugs, etc.) ## Contributing (creating issues, translations, fixing bugs, etc.)

View File

@@ -1,7 +1,7 @@
plugins { plugins {
id "java" id "java"
id "org.springframework.boot" version "3.3.0" id "org.springframework.boot" version "3.3.0"
id "io.spring.dependency-management" version "1.1.6" id "io.spring.dependency-management" version "1.1.5"
id "org.springdoc.openapi-gradle-plugin" version "1.8.0" id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
id "io.swagger.swaggerhub" version "1.3.2" id "io.swagger.swaggerhub" version "1.3.2"
id "edu.sc.seis.launch4j" version "3.0.5" id "edu.sc.seis.launch4j" version "3.0.5"
@@ -12,11 +12,11 @@ plugins {
import com.github.jk1.license.render.* import com.github.jk1.license.render.*
ext { ext {
springBootVersion = "3.3.2" springBootVersion = "3.3.0"
} }
group = "stirling.software" group = "stirling.software"
version = "0.26.2" version = "0.26.1"
// 17 is lowest but we support and recommend 21 // 17 is lowest but we support and recommend 21
sourceCompatibility = "17" sourceCompatibility = "17"
@@ -40,7 +40,6 @@ sourceSets {
exclude "stirling/software/SPDF/controller/web/AccountWebController.java" exclude "stirling/software/SPDF/controller/web/AccountWebController.java"
exclude "stirling/software/SPDF/controller/web/DatabaseWebController.java" exclude "stirling/software/SPDF/controller/web/DatabaseWebController.java"
exclude "stirling/software/SPDF/model/ApiKeyAuthenticationToken.java" exclude "stirling/software/SPDF/model/ApiKeyAuthenticationToken.java"
exclude "stirling/software/SPDF/model/AttemptCounter.java"
exclude "stirling/software/SPDF/model/Authority.java" exclude "stirling/software/SPDF/model/Authority.java"
exclude "stirling/software/SPDF/model/PersistentLogin.java" exclude "stirling/software/SPDF/model/PersistentLogin.java"
exclude "stirling/software/SPDF/model/User.java" exclude "stirling/software/SPDF/model/User.java"

View File

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

View File

@@ -62,10 +62,8 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }} imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext: securityContext:
{{- toYaml .Values.containerSecurityContext | nindent 10 }} {{- toYaml .Values.containerSecurityContext | nindent 10 }}
env:
- name: SYSTEM_ROOTURIPATH
value: {{ .Values.rootPath}}
{{- if .Values.envs }} {{- if .Values.envs }}
env:
{{ toYaml .Values.envs | indent 8 }} {{ toYaml .Values.envs | indent 8 }}
{{- end }} {{- end }}
{{- if .Values.extraArgs }} {{- if .Values.extraArgs }}
@@ -77,13 +75,13 @@ spec:
containerPort: 8080 containerPort: 8080
livenessProbe: livenessProbe:
httpGet: httpGet:
path: {{ .Values.rootPath}} path: /
port: http port: http
{{ toYaml .Values.probes.livenessHttpGetConfig | indent 12 }} {{ toYaml .Values.probes.livenessHttpGetConfig | indent 12 }}
{{ toYaml .Values.probes.liveness | indent 10 }} {{ toYaml .Values.probes.liveness | indent 10 }}
readinessProbe: readinessProbe:
httpGet: httpGet:
path: {{ .Values.rootPath}} path: /
port: http port: http
{{ toYaml .Values.probes.readinessHttpGetConfig | indent 12 }} {{ toYaml .Values.probes.readinessHttpGetConfig | indent 12 }}
{{ toYaml .Values.probes.readiness | indent 10 }} {{ toYaml .Values.probes.readiness | indent 10 }}

View File

@@ -15,9 +15,6 @@ secret:
commonLabels: {} commonLabels: {}
# team_name: dev # team_name: dev
# rootpath for the application
rootPath: /
envs: [] envs: []
# - name: UI_APP_NAME # - name: UI_APP_NAME
# value: "Stirling PDF" # value: "Stirling PDF"
@@ -27,6 +24,8 @@ envs: []
# value: "Stirling PDF" # value: "Stirling PDF"
# - name: ALLOW_GOOGLE_VISIBILITY # - name: ALLOW_GOOGLE_VISIBILITY
# value: "true" # value: "true"
# - name: APP_ROOT_PATH
# value: "/"
# - name: APP_LOCALE # - name: APP_LOCALE
# value: "en_GB" # value: "en_GB"

View File

@@ -1,106 +0,0 @@
%PDF-1.3
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
4 0 obj
<<
/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/Contents 11 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/PageMode /UseNone /Pages 8 0 R /Type /Catalog
>>
endobj
7 0 obj
<<
/Author (anonymous) /CreationDate (D:20240718233034+00'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20240718233034+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (unspecified) /Title (untitled) /Trapped /False
>>
endobj
8 0 obj
<<
/Count 3 /Kids [ 3 0 R 4 0 R 5 0 R ] /Type /Pages
>>
endobj
9 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 210
>>
stream
Gap@Gb79+X'F"5[`EfJOD4:mD<%*=m+N>oDG,>NK`<U'B^0WYY,dWl^i_UcRk`<"L=<NPC$BtQ<5l$3<Y!?BuoCSYQ6GSt25lpqr0IrP?S[b)9%M"e'HHFqcRO'9eRaR0'DYi*Y.:nEMFAoTM;rPL%EF]`CfoELVl_Q,"LS:%iI;Nc[&bG.*65O]ecfK1'*<>5P_s[usI/ph*0pV~>endstream
endobj
10 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@Gb79+X'F"5Y`EfJOV2A9=!fB]F'tK1LS`,]G+MiTenb&V2-^hqa(5IE#Nr59/!"Qm*5_(BdF!0&h!Yhk/A+\iS'%6tuO$O)9LaZS+flr([1p2&#RS1p/gT[B;rDj-=&=iqUlj(P^/5U@eCFqn4:<lU`l`.HXqG-',hJH.DI.(6L\luSAW`Q'oje[qgVLVIXg%PXe+,<$7('~>endstream
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@GbmK%f(e+0_`ODoa2.):e/i+N3r(.o*Qf\gSNb(bt4FIubi@GIOE=p8Ir3;CbQ@KuG^cdJhODZKQ*upt+*rdZ%!mFmN$*.P)K;`s#]G=8AO3s3DGB.RCOn?[F]bEIg,a>25?B%dh\Z/C6opFE'el@I,P\u\V\]:*JYrrsNJ&d,11VL;$h!43eGu&1X6$+5-h\Vr6!+>4Je,~>endstream
endobj
xref
0 12
0000000000 65535 f
0000000073 00000 n
0000000104 00000 n
0000000211 00000 n
0000000404 00000 n
0000000598 00000 n
0000000792 00000 n
0000000860 00000 n
0000001156 00000 n
0000001227 00000 n
0000001527 00000 n
0000001827 00000 n
trailer
<<
/ID
[<0d5cf047e754e05f8d574f067785875c><0d5cf047e754e05f8d574f067785875c>]
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
/Info 7 0 R
/Root 6 0 R
/Size 12
>>
startxref
2127
%%EOF

View File

@@ -1,106 +0,0 @@
%PDF-1.3
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
4 0 obj
<<
/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/Contents 11 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/PageMode /UseNone /Pages 8 0 R /Type /Catalog
>>
endobj
7 0 obj
<<
/Author (anonymous) /CreationDate (D:20240718233034+00'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20240718233034+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (unspecified) /Title (untitled) /Trapped /False
>>
endobj
8 0 obj
<<
/Count 3 /Kids [ 3 0 R 4 0 R 5 0 R ] /Type /Pages
>>
endobj
9 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 207
>>
stream
Gap@G:CDb.*/<p2MVk["e@)7*Z0@"b%+@f/9pA%_U<oOkVp?PnGRb81iPg?0i?(]%^_CSf##%;<!7Ne/-%RR^p@t7hKYZ9eJVHV]fjjHIB:6DrW+2\p16@*`r^CpQZZH'2Pjqd<.&hM2UO%$Wi$te%4QmS;<E"QS\!deQG_XtuEK>b(UbS>%`/0S`k\\5'TNY0mmgH?`8]i_0~>endstream
endobj
10 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 207
>>
stream
Gap@G]afWJ'Lm;=if<;s>V*7BTJ]oQ@P!(q5S+WG1%>L@?8Ue;c>[fY&&IOd5@t@TY@+q.5T<Z'81"J("KhsBa+&u4"n'#6)AjfImh)%$0tVC:aGk",=aJJH#/4]i.WJr9c"cibYm:M-44<%FFlG0Cl\Z'nmo7C"TR+7dk3T#iD(9Pq'\;rQku%o>A_`50SO&7M04=8M'O<Am~>endstream
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@GYmu@>'Ld5[if35r/JNaJ.A.7fP9RpSN*8k^-sEER0,enq1Rsuo@R/uCO-^&Y`F'9d^a?9)?ns+F&dXm[HMgPn6Ep+%TRk5Nh+!(+[H#H:U^.^(YL,PKS'%j/:3O\hJVEK-UUekJTd[A$N^((K^#0Du`i@,/^f5KiUISGr")3/+f9NF8NO1+iUgm^b"X\cE^+[:s!0]Gu6i~>endstream
endobj
xref
0 12
0000000000 65535 f
0000000073 00000 n
0000000104 00000 n
0000000211 00000 n
0000000404 00000 n
0000000598 00000 n
0000000792 00000 n
0000000860 00000 n
0000001156 00000 n
0000001227 00000 n
0000001524 00000 n
0000001822 00000 n
trailer
<<
/ID
[<407fc55425168745e56176202aad30c9><407fc55425168745e56176202aad30c9>]
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
/Info 7 0 R
/Root 6 0 R
/Size 12
>>
startxref
2122
%%EOF

View File

@@ -1,106 +0,0 @@
%PDF-1.3
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
4 0 obj
<<
/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/Contents 11 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/PageMode /UseNone /Pages 8 0 R /Type /Catalog
>>
endobj
7 0 obj
<<
/Author (anonymous) /CreationDate (D:20240718233034+00'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20240718233034+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (unspecified) /Title (untitled) /Trapped /False
>>
endobj
8 0 obj
<<
/Count 3 /Kids [ 3 0 R 4 0 R 5 0 R ] /Type /Pages
>>
endobj
9 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@G]+0EH(e/_@iZH]:>:>hu1e>07BJg5<'#:.C1n)e#(QJ6R1Rsuo_gpn.+0-H5$/#"iYR[B.9\'>7!aDAC*rf/t&6O#aH<?-7IT'\?X(&TcABG=ON*Nq`4k=o&p@3,0*31r<)TAP2Pk94p0\"R-_sY1$AYo[8B\?4R>feLAB\mpjZhp"`@J3;"Fm97#9+W,"eb95\+#p\^HN~>endstream
endobj
10 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@G]+0EX'Eriuig+>QHNeD'#n%Sq#n%BW`C'uDUOYK)HdS4E9JMsp+HUmDj&H-t*4?UamXX0peVspk"i_@ba+&u"J>UYDKV_^G,7V==aTZZ<YO7:sNSQ[6"Ja-29NtYjd#=`J@D'h+[QW=:EEb?A<k!f+\`g^?,Vgp7_)91[lR\f.Tkf7VIPLVYM&deF!aYt9Ip^"N",3F'*W~>endstream
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@G]+0EH(e/_@iZH]:>J`g!jPCLm;?AgU"fdk"PQZD\d?lRI_oWc[$tp^]O\:3fK8kWeX2&Jcg0+RoJ]j;2j*upu!b4.o&f)b$I@7CfIYjP^#\VjhC=QhQ]^lV-@<0Tam!0.+Dn@("AK%N,Uc7hb+6VoQ$q2q[7]BB92RoY/.j2N028i1jNf'@<1+Fqf$1&"8omHk`#DHP>OT~>endstream
endobj
xref
0 12
0000000000 65535 f
0000000073 00000 n
0000000104 00000 n
0000000211 00000 n
0000000404 00000 n
0000000598 00000 n
0000000792 00000 n
0000000860 00000 n
0000001156 00000 n
0000001227 00000 n
0000001526 00000 n
0000001826 00000 n
trailer
<<
/ID
[<80da26147a484f2b7573da8151a93d2e><80da26147a484f2b7573da8151a93d2e>]
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
/Info 7 0 R
/Root 6 0 R
/Size 12
>>
startxref
2126
%%EOF

File diff suppressed because it is too large Load Diff

View File

@@ -1,106 +0,0 @@
%PDF-1.3
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
4 0 obj
<<
/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/Contents 11 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/PageMode /UseNone /Pages 8 0 R /Type /Catalog
>>
endobj
7 0 obj
<<
/Author (anonymous) /CreationDate (D:20240718233034+00'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20240718233034+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (unspecified) /Title (untitled) /Trapped /False
>>
endobj
8 0 obj
<<
/Count 3 /Kids [ 3 0 R 4 0 R 5 0 R ] /Type /Pages
>>
endobj
9 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 206
>>
stream
Gap@G\IO3f&4Lr[@S4&T2aReWZ3N'9",Ncra>5AuK^J(o@r?=EP>b]h[L@XZ8q7#[c:#H2:^/=b,p3^,&f-Q.'H%!U?%N\iVa1pLMlh/41\A8@dF5@0al:-1?L;D%LpL3g\9`.3c6N/Mp=sE/nO%^@%Cc3`]e`qqS@[pkUWemMZC<P\fkqa55u)*hIUoU437-gb!e_*&B/,&~>endstream
endobj
10 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@G\IO3V'LdA_ig"8P1PS=kA5Q_GQ\P]*S3\>Q`jHYt?8UdkV`6]UV*On)+1VMV+A@.iF:*6sWfM9f"s.NmVuMto!p7-+,Rb<.h,pdi-&OQ5KO\RRFj.j"A)ScTQ7$hudF^TnZ'XuQA5"O]rYkt><-DJmj'"Ri>n!4`^m409XX`e)AR'*rGsn6m79.18+^ba=qRuss"-A3k+9~>endstream
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 210
>>
stream
Gap@G]+0EH(e/_@iZH]:.1fBHK`Xl'[i1&AjX(\k8hbgo(QJ6R1Rsuo6_I1A5Gg$JL;D#$J2CX;+Cf*cUHk2%H1XmpWe+qZ5moJ#B]>b%%[d,mfSSkS4A:Q4NlOFfrL7eA,s45"eUSakM;927AA,1"-LZ)&nZ/ah=8_X7:?ZMj@J@;r7d`t]Z0\d39M%:$k8[S5D"2oSap4s80l?~>endstream
endobj
xref
0 12
0000000000 65535 f
0000000073 00000 n
0000000104 00000 n
0000000211 00000 n
0000000404 00000 n
0000000598 00000 n
0000000792 00000 n
0000000860 00000 n
0000001156 00000 n
0000001227 00000 n
0000001523 00000 n
0000001823 00000 n
trailer
<<
/ID
[<88edee24ee67bd7d6b7cf53cfa2222b0><88edee24ee67bd7d6b7cf53cfa2222b0>]
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
/Info 7 0 R
/Root 6 0 R
/Size 12
>>
startxref
2124
%%EOF

View File

@@ -1,106 +0,0 @@
%PDF-1.3
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
4 0 obj
<<
/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/Contents 11 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/PageMode /UseNone /Pages 8 0 R /Type /Catalog
>>
endobj
7 0 obj
<<
/Author (anonymous) /CreationDate (D:20240718233034+00'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20240718233034+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (unspecified) /Title (untitled) /Trapped /False
>>
endobj
8 0 obj
<<
/Count 3 /Kids [ 3 0 R 4 0 R 5 0 R ] /Type /Pages
>>
endobj
9 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@GYmu@>'Ld5[if35rI0]sG)F[U^"c>T)"\\os-r:1V0,enq1Rsuo,*67.@k7U.LRF-P.e"CM2V!>iYi<g`nXh!K?n@$t^rY1$+^0'>=B8H6e;F1WmG#,(eS00(Qe9&:O@nI879DTsT,njXAB?`8:>,Hn3*RV!qh4;&@6%]<9Y*>QZ].Z5o;RAZXg7d[#+bphHs_Ep!QR2TZ2~>endstream
endobj
10 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 210
>>
stream
Gap@G]+0EH(e/_@iZH]:>=,iY1bE)XN?M;1'J/>i&HY;gks]*rj:!DKpb8@`prC#N+9E#o#-<G*!#p7e6j-1sX2k5S,6XmM"taYkfK^k">%usEeEk=sR<UT"dm`rXD;!S`_jS9LU+(R%e'V%WSMfHP.pXZEQqTQq=&D[I[PS(41(NIAZ1R/U?:Z=hSXu!NDF)bpG2F+/I/q/u1-Y~>endstream
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 209
>>
stream
Gap@G_$YcZ'LhbF`EQB$nqi=8S<;#HbK3&f>rnodRPo`Vf4P[3cJidY(I=[K5NWCT'<lHgci?oCRVNST&[k#q4oSC0FWgAt1pD4d_(hIRjn_Nt+cFgJlfm[1U8@/M4r^Pk<@F!@e?%/!-Vq;]nfdLi9]P2M)ck9?)%oNXa_\N<-d"(pjlH%-G`T@Sj&P(j6.@#Xh\Vr6!1iI2/H~>endstream
endobj
xref
0 12
0000000000 65535 f
0000000073 00000 n
0000000104 00000 n
0000000211 00000 n
0000000404 00000 n
0000000598 00000 n
0000000792 00000 n
0000000860 00000 n
0000001156 00000 n
0000001227 00000 n
0000001526 00000 n
0000001827 00000 n
trailer
<<
/ID
[<4fcc82a085fe71e34a32d1b23c8b939f><4fcc82a085fe71e34a32d1b23c8b939f>]
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
/Info 7 0 R
/Root 6 0 R
/Size 12
>>
startxref
2127
%%EOF

View File

@@ -14,8 +14,3 @@ def after_scenario(context, scenario):
os.remove('response_file') os.remove('response_file')
if hasattr(context, 'file_name') and os.path.exists(context.file_name): if hasattr(context, 'file_name') and os.path.exists(context.file_name):
os.remove(context.file_name) os.remove(context.file_name)
# Remove any temporary files
for temp_file in os.listdir('.'):
if temp_file.startswith('genericNonCustomisableName') or temp_file.startswith('temp_image_'):
os.remove(temp_file)

View File

@@ -1,4 +1,4 @@
@example @general @example
Feature: API Validation Feature: API Validation
@positive @password @positive @password
@@ -92,10 +92,10 @@ Feature: API Validation
| threshold | 90 | | threshold | 90 |
| whitePercent | 99.9 | | whitePercent | 99.9 |
When I send the API request to the endpoint "/api/v1/misc/remove-blanks" When I send the API request to the endpoint "/api/v1/misc/remove-blanks"
Then the response content type should be "application/octet-stream" Then the response content type should be "application/pdf"
And the response file should have extension ".zip"
And the response ZIP should contain 2 files
And the response file should have size greater than 0 And the response file should have size greater than 0
And the response PDF should contain 0 pages
And the response status code should be 200
@positive @flatten @positive @flatten
Scenario: Flatten PDF Scenario: Flatten PDF

View File

@@ -32,7 +32,7 @@ Feature: API Validation
@ocr @positive @ocr @positive
Scenario: Extract Image Scans Scenario: Extract Image Scans
Given I generate a PDF file as "fileInput" Given I generate a PDF file as "fileInput"
And the pdf contains 3 images of size 300x300 on 2 pages And the pdf contains 3 images on 2 pages
And the request data includes And the request data includes
| parameter | value | | parameter | value |
| angleThreshold | 5 | | angleThreshold | 5 |
@@ -125,7 +125,8 @@ Feature: API Validation
@ocr @ocr
Scenario: PDFA Scenario: PDFA
Given I use an example file at "exampleFiles/pdfa2.pdf" as parameter "fileInput" Given I generate a PDF file as "fileInput"
And the pdf contains 3 pages with random text
And the request data includes And the request data includes
| parameter | value | | parameter | value |
| outputFormat | pdfa | | outputFormat | pdfa |
@@ -136,7 +137,8 @@ Feature: API Validation
@ocr @ocr
Scenario: PDFA1 Scenario: PDFA1
Given I use an example file at "exampleFiles/pdfa1.pdf" as parameter "fileInput" Given I generate a PDF file as "fileInput"
And the pdf contains 3 pages with random text
And the request data includes And the request data includes
| parameter | value | | parameter | value |
| outputFormat | pdfa-1 | | outputFormat | pdfa-1 |
@@ -147,7 +149,8 @@ Feature: API Validation
@compress @ghostscript @positive @compress @ghostscript @positive
Scenario: Compress Scenario: Compress
Given I use an example file at "exampleFiles/ghost3.pdf" as parameter "fileInput" Given I generate a PDF file as "fileInput"
And the pdf contains 3 pages with random text
And the request data includes And the request data includes
| parameter | value | | parameter | value |
| optimizeLevel | 4 | | optimizeLevel | 4 |
@@ -158,7 +161,8 @@ Feature: API Validation
@compress @ghostscript @positive @compress @ghostscript @positive
Scenario: Compress Scenario: Compress
Given I use an example file at "exampleFiles/ghost2.pdf" as parameter "fileInput" Given I generate a PDF file as "fileInput"
And the pdf contains 3 pages with random text
And the request data includes And the request data includes
| parameter | value | | parameter | value |
| optimizeLevel | 1 | | optimizeLevel | 1 |
@@ -171,7 +175,8 @@ Feature: API Validation
@compress @ghostscript @positive @compress @ghostscript @positive
Scenario: Compress Scenario: Compress
Given I use an example file at "exampleFiles/ghost1.pdf" as parameter "fileInput" Given I generate a PDF file as "fileInput"
And the pdf contains 3 pages with random text
And the request data includes And the request data includes
| parameter | value | | parameter | value |
| optimizeLevel | 1 | | optimizeLevel | 1 |

View File

@@ -94,23 +94,3 @@ Feature: API Validation
| 1 | 10 | 2 | 10 | | 1 | 10 | 2 | 10 |
@extract-images
Scenario Outline: Extract Image Scans
Given I use an example file at "exampleFiles/images.pdf" as parameter "fileInput"
And the request data includes
| parameter | value |
| format | <format> |
When I send the API request to the endpoint "/api/v1/misc/extract-images"
Then the response content type should be "application/octet-stream"
And the response file should have extension ".zip"
And the response ZIP should contain 20 files
And the response file should have size greater than 0
And the response status code should be 200
Examples:
| format |
| png |
| gif |
| jpeg |

View File

@@ -6,14 +6,11 @@ import io
import random import random
import string import string
from reportlab.lib.pagesizes import letter from reportlab.lib.pagesizes import letter
from reportlab.lib.utils import ImageReader
from reportlab.pdfgen import canvas from reportlab.pdfgen import canvas
import mimetypes import mimetypes
import requests import requests
import zipfile import zipfile
import shutil import shutil
import re
from PIL import Image, ImageDraw
######### #########
# GIVEN # # GIVEN #
@@ -46,6 +43,8 @@ def step_use_example_file(context, filePath, fileInput):
except FileNotFoundError: except FileNotFoundError:
raise FileNotFoundError(f"The example file '{filePath}' does not exist.") raise FileNotFoundError(f"The example file '{filePath}' does not exist.")
@given('the pdf contains {page_count:d} pages') @given('the pdf contains {page_count:d} pages')
def step_pdf_contains_pages(context, page_count): def step_pdf_contains_pages(context, page_count):
writer = PdfWriter() writer = PdfWriter()
@@ -67,6 +66,8 @@ def step_pdf_contains_blank_pages(context, page_count):
context.files[context.param_name].close() context.files[context.param_name].close()
context.files[context.param_name] = open(context.file_name, 'rb') context.files[context.param_name] = open(context.file_name, 'rb')
def create_black_box_image(file_name, size): def create_black_box_image(file_name, size):
can = canvas.Canvas(file_name, pagesize=size) can = canvas.Canvas(file_name, pagesize=size)
width, height = size width, height = size
@@ -75,25 +76,9 @@ def create_black_box_image(file_name, size):
can.showPage() can.showPage()
can.save() can.save()
@given(u'the pdf contains {image_count:d} images of size {width:d}x{height:d} on {page_count:d} pages') def create_pdf_with_black_boxes(file_name, image_count, page_count):
def step_impl(context, image_count, width, height, page_count): page_width, page_height = letter
context.param_name = "fileInput" box_size = 72 # 1 inch by 1 inch black box
context.file_name = "genericNonCustomisableName.pdf"
create_pdf_with_images_and_boxes(context.file_name, image_count, page_count, width, height)
if not hasattr(context, 'files'):
context.files = {}
context.files[context.param_name] = open(context.file_name, 'rb')
def add_black_boxes_to_image(image):
if isinstance(image, str):
image = Image.open(image)
draw = ImageDraw.Draw(image)
draw.rectangle([(0, 0), image.size], fill=(0, 0, 0)) # Fill image with black
return image
def create_pdf_with_images_and_boxes(file_name, image_count, page_count, image_width, image_height):
page_width, page_height = max(letter[0], image_width), max(letter[1], image_height)
boxes_per_page = image_count // page_count + (1 if image_count % page_count != 0 else 0) boxes_per_page = image_count // page_count + (1 if image_count % page_count != 0 else 0)
writer = PdfWriter() writer = PdfWriter()
@@ -101,31 +86,15 @@ def create_pdf_with_images_and_boxes(file_name, image_count, page_count, image_w
for page in range(page_count): for page in range(page_count):
packet = io.BytesIO() packet = io.BytesIO()
can = canvas.Canvas(packet, pagesize=(page_width, page_height)) can = canvas.Canvas(packet, pagesize=letter)
for i in range(boxes_per_page): for i in range(boxes_per_page):
if box_counter >= image_count: if box_counter >= image_count:
break break
x = (i % (page_width // box_size)) * box_size
# Simulating a dynamic image creation (replace this with your actual image creation logic) y = page_height - ((i // (page_width // box_size) + 1) * box_size)
# For demonstration, we'll create a simple black image can.setFillColorRGB(0, 0, 0)
dummy_image = Image.new('RGB', (image_width, image_height), color='white') # Create a white image can.rect(x, y, box_size, box_size, fill=1)
dummy_image = add_black_boxes_to_image(dummy_image) # Add black boxes
# Convert the PIL Image to bytes to pass to drawImage
image_bytes = io.BytesIO()
dummy_image.save(image_bytes, format='PNG')
image_bytes.seek(0)
# Check if the image fits in the current page dimensions
x = (i % (page_width // image_width)) * image_width
y = page_height - (((i % (page_height // image_height)) + 1) * image_height)
if x + image_width > page_width or y < 0:
break
# Add the image to the PDF
can.drawImage(ImageReader(image_bytes), x, y, width=image_width, height=image_height)
box_counter += 1 box_counter += 1
can.showPage() can.showPage()
@@ -134,16 +103,9 @@ def create_pdf_with_images_and_boxes(file_name, image_count, page_count, image_w
new_pdf = PdfReader(packet) new_pdf = PdfReader(packet)
writer.add_page(new_pdf.pages[0]) writer.add_page(new_pdf.pages[0])
# Write the PDF to file
with open(file_name, 'wb') as f: with open(file_name, 'wb') as f:
writer.write(f) writer.write(f)
# Clean up temporary image files
for i in range(image_count):
temp_image_path = f"temp_image_{i}.png"
if os.path.exists(temp_image_path):
os.remove(temp_image_path)
@given('the pdf contains {image_count:d} images on {page_count:d} pages') @given('the pdf contains {image_count:d} images on {page_count:d} pages')
def step_pdf_contains_images(context, image_count, page_count): def step_pdf_contains_images(context, image_count, page_count):
if not hasattr(context, 'param_name'): if not hasattr(context, 'param_name'):
@@ -156,6 +118,7 @@ def step_pdf_contains_images(context, image_count, page_count):
context.files[context.param_name].close() context.files[context.param_name].close()
context.files[context.param_name] = open(context.file_name, 'rb') context.files[context.param_name] = open(context.file_name, 'rb')
@given('the pdf contains {page_count:d} pages with random text') @given('the pdf contains {page_count:d} pages with random text')
def step_pdf_contains_pages_with_random_text(context, page_count): def step_pdf_contains_pages_with_random_text(context, page_count):
buffer = io.BytesIO() buffer = io.BytesIO()
@@ -223,21 +186,6 @@ def save_generated_pdf(context, filename):
# WHEN # # WHEN #
######## ########
@when('I send a GET request to "{endpoint}"')
def step_send_get_request(context, endpoint):
base_url = "http://localhost:8080"
full_url = f"{base_url}{endpoint}"
response = requests.get(full_url)
context.response = response
@when('I send a GET request to "{endpoint}" with parameters')
def step_send_get_request_with_params(context, endpoint):
base_url = "http://localhost:8080"
params = {row['parameter']: row['value'] for row in context.table}
full_url = f"{base_url}{endpoint}"
response = requests.get(full_url, params=params)
context.response = response
@when('I send the API request to the endpoint "{endpoint}"') @when('I send the API request to the endpoint "{endpoint}"')
def step_send_api_request(context, endpoint): def step_send_api_request(context, endpoint):
url = f"http://localhost:8080{endpoint}" url = f"http://localhost:8080{endpoint}"
@@ -330,6 +278,7 @@ def step_save_response_file(context, filename):
f.write(context.response.content) f.write(context.response.content)
print(f"Saved response content to {filename}") print(f"Saved response content to {filename}")
@then('the response PDF should contain {page_count:d} pages') @then('the response PDF should contain {page_count:d} pages')
def step_check_response_pdf_page_count(context, page_count): def step_check_response_pdf_page_count(context, page_count):
response_file = io.BytesIO(context.response.content) response_file = io.BytesIO(context.response.content)
@@ -356,26 +305,3 @@ def step_check_response_zip_doc_page_count(context, doc_count, pages_per_doc):
reader = PdfReader(pdf_file) reader = PdfReader(pdf_file)
actual_pages_per_doc = len(reader.pages) actual_pages_per_doc = len(reader.pages)
assert actual_pages_per_doc == pages_per_doc, f"Expected {pages_per_doc} pages per document but got {actual_pages_per_doc} pages in document {file_name}" assert actual_pages_per_doc == pages_per_doc, f"Expected {pages_per_doc} pages per document but got {actual_pages_per_doc} pages in document {file_name}"
@then('the JSON value of "{key}" should be "{expected_value}"')
def step_check_json_value(context, key, expected_value):
actual_value = context.response.json().get(key)
assert actual_value == expected_value, \
f"Expected JSON value for '{key}' to be '{expected_value}' but got '{actual_value}'"
@then('JSON list entry containing "{identifier_key}" as "{identifier_value}" should have "{target_key}" as "{target_value}"')
def step_check_json_list_entry(context, identifier_key, identifier_self, target_key, target_value):
json_response = context.response.json()
for entry in json_response:
if entry.get(identifier_key) == identifier_value:
assert entry.get(target_key) == target_value, \
f"Expected {target_key} to be {target_value} in entry where {identifier_key} is {identifier_value}, but found {entry.get(target_key)}"
break
else:
raise AssertionError(f"No entry with {identifier_key} as {identifier_value} found")
@then('the response should match the regex "{pattern}"')
def step_response_matches_regex(context, pattern):
response_text = context.response.text
assert re.match(pattern, response_text), \
f"Response '{response_text}' does not match the expected pattern '{pattern}'"

View File

@@ -22,6 +22,7 @@ services:
DOCKER_ENABLE_SECURITY: "false" DOCKER_ENABLE_SECURITY: "false"
SECURITY_ENABLELOGIN: "false" SECURITY_ENABLELOGIN: "false"
LANGS: "en_GB,en_US,ar_AR,de_DE,fr_FR,es_ES,zh_CN,zh_TW,ca_CA,it_IT,sv_SE,pl_PL,ro_RO,ko_KR,pt_BR,ru_RU,el_GR,hi_IN,hu_HU,tr_TR,id_ID" LANGS: "en_GB,en_US,ar_AR,de_DE,fr_FR,es_ES,zh_CN,zh_TW,ca_CA,it_IT,sv_SE,pl_PL,ro_RO,ko_KR,pt_BR,ru_RU,el_GR,hi_IN,hu_HU,tr_TR,id_ID"
INSTALL_BOOK_AND_ADVANCED_HTML_OPS: "true"
SYSTEM_DEFAULTLOCALE: en-US SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest

View File

@@ -25,11 +25,6 @@ ignore = [
'text', 'text',
] ]
[da_DK]
ignore = [
'language.direction',
]
[de_DE] [de_DE]
ignore = [ ignore = [
'AddStampRequest.alphabet', 'AddStampRequest.alphabet',
@@ -92,11 +87,6 @@ ignore = [
'watermark.type.2', 'watermark.type.2',
] ]
[ga_IE]
ignore = [
'language.direction',
]
[hi_IN] [hi_IN]
ignore = [ ignore = [
'language.direction', 'language.direction',
@@ -222,14 +212,6 @@ ignore = [
'language.direction', 'language.direction',
] ]
[th_TH]
ignore = [
'language.direction',
'pipeline.title',
'pipelineOptions.pipelineHeader',
'showJS.tags',
]
[tr_TR] [tr_TR]
ignore = [ ignore = [
'language.direction', 'language.direction',
@@ -240,14 +222,6 @@ ignore = [
'language.direction', 'language.direction',
] ]
[vi_VN]
ignore = [
'language.direction',
'pipeline.title',
'pipelineOptions.pipelineHeader',
'showJS.tags',
]
[zh_CN] [zh_CN]
ignore = [ ignore = [
'language.direction', 'language.direction',

View File

@@ -12,8 +12,7 @@ fi
umask "$UMASK" || true umask "$UMASK" || true
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" && "$FAT_DOCKER" != "true" ]]; then if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" && "$FAT_DOCKER" != "true" ]]; then
echo "issue with calibre in current version, feature currently disabled on Stirling-PDF" apk add --no-cache calibre@testing
#apk add --no-cache calibre@testing
fi fi
if [[ "$FAT_DOCKER" != "true" ]]; then if [[ "$FAT_DOCKER" != "true" ]]; then

View File

@@ -45,6 +45,7 @@ public class SPdfApplication {
// Check if the BROWSER_OPEN environment variable is set to true // Check if the BROWSER_OPEN environment variable is set to true
String browserOpenEnv = env.getProperty("BROWSER_OPEN"); String browserOpenEnv = env.getProperty("BROWSER_OPEN");
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv); boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
if (browserOpen) { if (browserOpen) {
try { try {
String url = "http://localhost:" + getNonStaticPort(); String url = "http://localhost:" + getNonStaticPort();
@@ -78,13 +79,13 @@ public class SPdfApplication {
// custom javs settings file // custom javs settings file
if (Files.exists(Paths.get("configs/custom_settings.yml"))) { if (Files.exists(Paths.get("configs/custom_settings.yml"))) {
String existingLocation = propertyFiles.getOrDefault("spring.config.additional-location", ""); String existing = propertyFiles.getOrDefault("spring.config.additional-location", "");
if (!existingLocation.isEmpty()) { if (!existing.isEmpty()) {
existingLocation += ","; existing += ",";
} }
propertyFiles.put( propertyFiles.put(
"spring.config.additional-location", "spring.config.additional-location",
existingLocation + "file:configs/custom_settings.yml"); existing + "file:configs/custom_settings.yml");
} else { } else {
logger.warn("Custom configuration file 'configs/custom_settings.yml' does not exist."); logger.warn("Custom configuration file 'configs/custom_settings.yml' does not exist.");
} }

View File

@@ -32,25 +32,25 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
String queryString = request.getQueryString(); String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) { if (queryString != null && !queryString.isEmpty()) {
String requestURI = request.getRequestURI(); String requestURI = request.getRequestURI();
Map<String, String> allowedParameters = new HashMap<>(); Map<String, String> parameters = new HashMap<>();
// Keep only the allowed parameters // Keep only the allowed parameters
String[] queryParameters = queryString.split("&"); String[] queryParameters = queryString.split("&");
for (String param : queryParameters) { for (String param : queryParameters) {
String[] keyValuePair = param.split("="); String[] keyValue = param.split("=");
if (keyValuePair.length != 2) { if (keyValue.length != 2) {
continue; continue;
} }
if (ALLOWED_PARAMS.contains(keyValuePair[0])) { if (ALLOWED_PARAMS.contains(keyValue[0])) {
allowedParameters.put(keyValuePair[0], keyValuePair[1]); parameters.put(keyValue[0], keyValue[1]);
} }
} }
// If there are any parameters that are not allowed // If there are any parameters that are not allowed
if (allowedParameters.size() != queryParameters.length) { if (parameters.size() != queryParameters.length) {
// Construct new query string // Construct new query string
StringBuilder newQueryString = new StringBuilder(); StringBuilder newQueryString = new StringBuilder();
for (Map.Entry<String, String> entry : allowedParameters.entrySet()) { for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (newQueryString.length() > 0) { if (newQueryString.length() > 0) {
newQueryString.append("&"); newQueryString.append("&");
} }

View File

@@ -8,7 +8,6 @@ import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
@@ -132,12 +131,11 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm"); DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
Path insertOutputFilePath = Path insertOutputFilePath =
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql"); this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;"; String query = "SCRIPT SIMPLE COLUMNS DROP to '" + insertOutputFilePath.toString() + "';";
try (Connection conn = DriverManager.getConnection(url, "sa", ""); try (Connection conn = DriverManager.getConnection(url, "sa", "");
PreparedStatement stmt = conn.prepareStatement(query)) { Statement stmt = conn.createStatement()) {
stmt.setString(1, insertOutputFilePath.toString()); stmt.execute(query);
stmt.execute();
log.info("Database export completed: {}", insertOutputFilePath); log.info("Database export completed: {}", insertOutputFilePath);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Error during database export: {}", e.getMessage(), e); log.error("Error during database export: {}", e.getMessage(), e);
@@ -179,12 +177,11 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
} }
private boolean executeDatabaseScript(Path scriptPath) { private boolean executeDatabaseScript(Path scriptPath) {
String query = "RUNSCRIPT from ?;";
try (Connection conn = DriverManager.getConnection(url, "sa", ""); try (Connection conn = DriverManager.getConnection(url, "sa", "");
PreparedStatement stmt = conn.prepareStatement(query)) { Statement stmt = conn.createStatement()) {
stmt.setString(1, scriptPath.toString());
stmt.execute(); String query = "RUNSCRIPT from '" + scriptPath.toString() + "';";
stmt.execute(query);
log.info("Database import completed: {}", scriptPath); log.info("Database import completed: {}", scriptPath);
return true; return true;
} catch (SQLException e) { } catch (SQLException e) {

View File

@@ -1,12 +1,12 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.zip.ZipEntry; import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream; import java.util.stream.IntStream;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
@@ -17,7 +17,6 @@ import org.apache.pdfbox.text.PDFTextStripper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -51,31 +50,31 @@ public class BlankPageController {
int threshold = request.getThreshold(); int threshold = request.getThreshold();
float whitePercent = request.getWhitePercent(); float whitePercent = request.getWhitePercent();
try (PDDocument document = Loader.loadPDF(inputFile.getBytes())) { PDDocument document = null;
try {
document = Loader.loadPDF(inputFile.getBytes());
PDPageTree pages = document.getDocumentCatalog().getPages(); PDPageTree pages = document.getDocumentCatalog().getPages();
PDFTextStripper textStripper = new PDFTextStripper(); PDFTextStripper textStripper = new PDFTextStripper();
List<PDPage> nonBlankPages = new ArrayList<>(); List<Integer> pagesToKeepIndex = new ArrayList<>();
List<PDPage> blankPages = new ArrayList<>();
int pageIndex = 0; int pageIndex = 0;
PDFRenderer pdfRenderer = new PDFRenderer(document); PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true); pdfRenderer.setSubsamplingAllowed(true);
for (PDPage page : pages) { for (PDPage page : pages) {
logger.info("checking page {}", pageIndex); logger.info("checking page " + pageIndex);
textStripper.setStartPage(pageIndex + 1); textStripper.setStartPage(pageIndex + 1);
textStripper.setEndPage(pageIndex + 1); textStripper.setEndPage(pageIndex + 1);
String pageText = textStripper.getText(document); String pageText = textStripper.getText(document);
boolean hasText = !pageText.trim().isEmpty(); boolean hasText = !pageText.trim().isEmpty();
boolean blank = true; Boolean blank = true;
if (hasText) { if (hasText) {
logger.info("page {} has text, not blank", pageIndex); logger.info("page " + pageIndex + " has text, not blank");
blank = false; blank = false;
} else { } else {
boolean hasImages = PdfUtils.hasImagesOnPage(page); boolean hasImages = PdfUtils.hasImagesOnPage(page);
if (hasImages) { if (hasImages) {
logger.info("page {} has image, running blank detection", pageIndex); logger.info("page " + pageIndex + " has image, running blank detection");
// Render image and save as temp file // Render image and save as temp file
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 30); BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 30);
blank = isBlankImage(image, threshold, whitePercent, threshold); blank = isBlankImage(image, threshold, whitePercent, threshold);
@@ -83,57 +82,34 @@ public class BlankPageController {
} }
if (blank) { if (blank) {
logger.info("Skipping, Image was blank for page #{}", pageIndex); logger.info("Skipping, Image was blank for page #" + pageIndex);
blankPages.add(page);
} else { } else {
logger.info("page {} has image which is not blank", pageIndex); logger.info("page " + pageIndex + " has image which is not blank");
nonBlankPages.add(page); pagesToKeepIndex.add(pageIndex);
} }
pageIndex++; pageIndex++;
} }
// Remove pages not present in pagesToKeepIndex
List<Integer> pageIndices =
IntStream.range(0, pages.getCount()).boxed().collect(Collectors.toList());
Collections.reverse(pageIndices); // Reverse to prevent index shifting during removal
for (Integer i : pageIndices) {
if (!pagesToKeepIndex.contains(i)) {
pages.remove(i);
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(); return WebResponseUtils.pdfDocToWebResponse(
ZipOutputStream zos = new ZipOutputStream(baos); document,
String filename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()) Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", ""); .replaceFirst("[.][^.]+$", "")
+ "_blanksRemoved.pdf");
if (!nonBlankPages.isEmpty()) {
createZipEntry(zos, nonBlankPages, filename + "_nonBlankPages.pdf");
} else {
createZipEntry(zos, blankPages, filename + "_allBlankPages.pdf");
}
if (!nonBlankPages.isEmpty() && !blankPages.isEmpty()) {
createZipEntry(zos, blankPages, filename + "_blankPages.pdf");
}
zos.close();
logger.info("Returning ZIP file: {}", filename + "_processed.zip");
return WebResponseUtils.boasToWebResponse(
baos, filename + "_processed.zip", MediaType.APPLICATION_OCTET_STREAM);
} catch (IOException e) { } catch (IOException e) {
logger.error("exception", e); logger.error("exception", e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} } finally {
} if (document != null) document.close();
public void createZipEntry(ZipOutputStream zos, List<PDPage> pages, String entryName)
throws IOException {
try (PDDocument document = new PDDocument()) {
for (PDPage page : pages) {
document.addPage(page);
}
ZipEntry zipEntry = new ZipEntry(entryName);
zos.putNextEntry(zipEntry);
document.save(zos);
zos.closeEntry();
} }
} }

View File

@@ -99,7 +99,7 @@ public class CompressController {
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
command.add("gs"); command.add("gs");
command.add("-sDEVICE=pdfwrite"); command.add("-sDEVICE=pdfwrite");
command.add("-dCompatibilityLevel=1.5"); command.add("-dCompatibilityLevel=1.4");
switch (optimizeLevel) { switch (optimizeLevel) {
case 1: case 1:

View File

@@ -68,7 +68,6 @@ public class PasswordController {
boolean canModifyAnnotations = request.isCanModifyAnnotations(); boolean canModifyAnnotations = request.isCanModifyAnnotations();
boolean canPrint = request.isCanPrint(); boolean canPrint = request.isCanPrint();
boolean canPrintFaithful = request.isCanPrintFaithful(); boolean canPrintFaithful = request.isCanPrintFaithful();
PDDocument document = Loader.loadPDF(fileInput.getBytes()); PDDocument document = Loader.loadPDF(fileInput.getBytes());
AccessPermission ap = new AccessPermission(); AccessPermission ap = new AccessPermission();
ap.setCanAssembleDocument(!canAssembleDocument); ap.setCanAssembleDocument(!canAssembleDocument);

View File

@@ -360,8 +360,6 @@ public class ApplicationProperties {
+ useAsUsername + useAsUsername
+ ", provider=" + ", provider="
+ provider + provider
+ ", client="
+ client
+ ", scopes=" + ", scopes="
+ scopes + scopes
+ "]"; + "]";

View File

@@ -3,11 +3,9 @@ package stirling.software.SPDF.repository;
import java.util.Set; import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.Authority; import stirling.software.SPDF.model.Authority;
@Repository
public interface AuthorityRepository extends JpaRepository<Authority, Long> { public interface AuthorityRepository extends JpaRepository<Authority, Long> {
// Set<Authority> findByUsername(String username); // Set<Authority> findByUsername(String username);
Set<Authority> findByUser_Username(String username); Set<Authority> findByUser_Username(String username);

View File

@@ -1,9 +1,7 @@
package stirling.software.SPDF.repository; package stirling.software.SPDF.repository;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.PersistentLogin; import stirling.software.SPDF.model.PersistentLogin;
@Repository
public interface PersistentLoginRepository extends JpaRepository<PersistentLogin, String> {} public interface PersistentLoginRepository extends JpaRepository<PersistentLogin, String> {}

View File

@@ -3,12 +3,10 @@ package stirling.software.SPDF.repository;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
@Repository public interface UserRepository extends JpaRepository<User, String> {
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsernameIgnoreCase(String username); Optional<User> findByUsernameIgnoreCase(String username);
Optional<User> findByUsername(String username); Optional<User> findByUsername(String username);

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Покажи проследяване на стека
error.copyStack=Копиране на проследяване на стека error.copyStack=Копиране на проследяване на стека
error.githubSubmit=GitHub - Изпратете запитване error.githubSubmit=GitHub - Изпратете запитване
error.discordSubmit=Discord - Изпратете запитване за поддръжка error.discordSubmit=Discord - Изпратете запитване за поддръжка

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Zobrazit stopu zásobníku
error.copyStack=Kopírovat stopu zásobníku error.copyStack=Kopírovat stopu zásobníku
error.githubSubmit=GitHub - Odeslat požadavek error.githubSubmit=GitHub - Odeslat požadavek
error.discordSubmit=Discord - Odeslat příspěvek podpory error.discordSubmit=Discord - Odeslat příspěvek podpory

File diff suppressed because it is too large Load Diff

View File

@@ -1124,3 +1124,4 @@ error.showStack=Stack-Trace anzeigen
error.copyStack=Stack-Trace kopieren error.copyStack=Stack-Trace kopieren
error.githubSubmit=GitHub - Ein Ticket einreichen error.githubSubmit=GitHub - Ein Ticket einreichen
error.discordSubmit=Discord - Unterstützungsbeitrag einreichen error.discordSubmit=Discord - Unterstützungsbeitrag einreichen

View File

@@ -1124,3 +1124,4 @@ error.showStack=Εμφάνιση Stack Trace
error.copyStack=Αντιγραφή Stack Trace error.copyStack=Αντιγραφή Stack Trace
error.githubSubmit=GitHub - Υποβάλετε ένα ticket error.githubSubmit=GitHub - Υποβάλετε ένα ticket
error.discordSubmit=Discord - Υποβάλετε ένα Support post error.discordSubmit=Discord - Υποβάλετε ένα Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -60,11 +60,11 @@ deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actua
deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse. deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse.
downgradeCurrentUserMessage=No se puede degradar el rol del usuario actual downgradeCurrentUserMessage=No se puede degradar el rol del usuario actual
downgradeCurrentUserLongMessage=No se puede degradar el rol del usuario actual. Por lo tanto, el usuario actual no se mostrará. downgradeCurrentUserLongMessage=No se puede degradar el rol del usuario actual. Por lo tanto, el usuario actual no se mostrará.
userAlreadyExistsOAuthMessage=La usuario ya existe como usuario de OAuth2. userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=El usuario ya existe como usuario web. userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Ups! oops=Ups!
help=Ayuda help=Help
goHomepage=Ir a la página principal goHomepage=Ir a la página principal
joinDiscord=Únase a nuestro servidor Discord joinDiscord=Únase a nuestro servidor Discord
seeDockerHub=Ver Docker Hub seeDockerHub=Ver Docker Hub
@@ -86,7 +86,7 @@ pipeline.defaultOption=Personalizar
pipeline.submitButton=Enviar pipeline.submitButton=Enviar
pipeline.help=Ayuda de Canalización pipeline.help=Ayuda de Canalización
pipeline.scanHelp=Ayuda de escaneado de carpetas pipeline.scanHelp=Ayuda de escaneado de carpetas
pipeline.deletePrompt=¿Estás segura de que quieres eliminar la canalización? pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -107,18 +107,18 @@ pipelineOptions.validateButton=Validar
############# #############
# NAVBAR # # NAVBAR #
############# #############
navbar.favorite=Favoritos navbar.favorite=Favorites
navbar.darkmode=Modo oscuro navbar.darkmode=Modo oscuro
navbar.language=Idiomas navbar.language=Languages
navbar.settings=Configuración navbar.settings=Configuración
navbar.allTools=Herramientas navbar.allTools=Tools
navbar.multiTool=Multi herramientas navbar.multiTool=Multi Tools
navbar.sections.organize=Organize navbar.sections.organize=Organize
navbar.sections.convertTo=Convertir a PDF navbar.sections.convertTo=Convert to PDF
navbar.sections.convertFrom=Convertir desde PDF navbar.sections.convertFrom=Convert from PDF
navbar.sections.security=Señalización y seguridad navbar.sections.security=Sign & Security
navbar.sections.advance=Avanzado navbar.sections.advance=Advanced
navbar.sections.edit=Ver y Editar navbar.sections.edit=View & Edit
############# #############
# SETTINGS # # SETTINGS #
@@ -175,8 +175,8 @@ adminUserSettings.header=Configuración de control de usuario administrador
adminUserSettings.admin=Administrador adminUserSettings.admin=Administrador
adminUserSettings.user=Usuario adminUserSettings.user=Usuario
adminUserSettings.addUser=Añadir Nuevo Usuario adminUserSettings.addUser=Añadir Nuevo Usuario
adminUserSettings.deleteUser=Eliminar Usuario adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=¿Se debe eliminar al usuario? adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=El nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida. adminUserSettings.usernameInfo=El nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Rol adminUserSettings.role=Rol
@@ -189,24 +189,24 @@ adminUserSettings.internalApiUser=Usuario interno de API
adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso
adminUserSettings.submit=Guardar Usuario adminUserSettings.submit=Guardar Usuario
adminUserSettings.changeUserRole=Cambiar rol de usuario adminUserSettings.changeUserRole=Cambiar rol de usuario
adminUserSettings.authenticated=Autenticado adminUserSettings.authenticated=Authenticated
database.title=Base de Datos Importar/Exportar database.title=Database Import/Export
database.header=Base de Datos Importar/Exportar database.header=Database Import/Export
database.fileName=Nombre de Archivo database.fileName=File Name
database.creationDate=Fecha de creación database.creationDate=Creation Date
database.fileSize=Tamaño de archivo database.fileSize=File Size
database.deleteBackupFile=Eliminar archivo de copia de seguridad database.deleteBackupFile=Delete Backup File
database.importBackupFile=Importar archivo de copia de seguridad database.importBackupFile=Import Backup File
database.downloadBackupFile=Descargar archivo de copia de seguridad database.downloadBackupFile=Download Backup File
database.info_1=Al importar datos, es fundamental garantizar la estructura correcta. Si no está seguro de lo que está haciendo, busque consejo y apoyo de un profesional. Un error en la estructura puede causar un mal funcionamiento de la aplicación, incluyendo la imposibilidad total de ejecutar la aplicación. database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application.
database.info_2=El nombre del archivo no importa al cargarlo. Posteriormente se le cambiará el nombre para que siga el formato backup_user_yyyyMMddHHmm.sql, lo que garantiza una convención de nomenclatura coherente. database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention.
database.submit=Importar Backup database.submit=Import Backup
database.importIntoDatabaseSuccessed=Importación a la base de datos ha sido exitosa database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=Archivo no encontrado database.fileNotFound=File not Found
database.fileNullOrEmpty=El archivo no debe ser nulo o vacío. database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=Archivo de importación fallido database.failedImportFile=Failed Import File
############# #############
# HOME-PAGE # # HOME-PAGE #
@@ -353,8 +353,8 @@ home.certSign.title=Firmar con certificado
home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12) home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12)
certSign.tags=autentificar,PEM,P12,oficial,encriptar certSign.tags=autentificar,PEM,P12,oficial,encriptar
home.removeCertSign.title=Quitar signo de certificado home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Eliminar firma de certificado de PDF home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Diseño de varias páginas home.pageLayout.title=Diseño de varias páginas
@@ -476,13 +476,13 @@ login.invalid=Nombre de usuario o contraseña erróneos.
login.locked=Su cuenta se ha bloqueado. login.locked=Su cuenta se ha bloqueado.
login.signinTitle=Por favor, inicie sesión login.signinTitle=Por favor, inicie sesión
login.ssoSignIn=Iniciar sesión a través del inicio de sesión único login.ssoSignIn=Iniciar sesión a través del inicio de sesión único
login.oauth2AutoCreateDisabled=Usuario de creación automática de OAUTH2 DESACTIVADO login.oauth2AutoCreateDisabled=Usuario DE creación automática de OAUTH2 DESACTIVADO
login.oauth2RequestNotFound=Solicitud de autorización no encontrada login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Respuesta de información de usuario no válida login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Invalid Request
login.oauth2AccessDenied=Access Denied login.oauth2AccessDenied=Access Denied
login.oauth2InvalidTokenResponse=Respuesta de token no válida login.oauth2InvalidTokenResponse=Invalid Token Response
login.oauth2InvalidIdToken=Token de identificación no válido login.oauth2InvalidIdToken=Invalid Id Token
#auto-redact #auto-redact
@@ -681,10 +681,10 @@ certSign.submit=Firmar PDF
#removeCertSign #removeCertSign
removeCertSign.title=Eliminar firma del certificado removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Quitar el certificado digital del PDF removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Seleccione un archivo PDF: removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Eliminar firma removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
@@ -706,8 +706,8 @@ removeAnnotations.submit=Eliminar
#compare #compare
compare.title=Comparar compare.title=Comparar
compare.header=Comparar archivos PDF compare.header=Comparar archivos PDF
compare.highlightColor.1=Color resaltado 1: compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Color resaltado 2: compare.highlightColor.2=Highlight Color 2:
compare.document.1=Documento 1 compare.document.1=Documento 1
compare.document.2=Documento 2 compare.document.2=Documento 2
compare.submit=Comparar compare.submit=Comparar
@@ -744,7 +744,7 @@ repair.submit=Reparar
#flatten #flatten
flatten.title=Aplanar flatten.title=Aplanar
flatten.header=Acoplar archivos PDF flatten.header=Acoplar archivos PDF
flatten.flattenOnlyForms=Aplanar sólo formularios flatten.flattenOnlyForms=Flatten only forms
flatten.submit=Aplanar flatten.submit=Aplanar
@@ -792,7 +792,7 @@ extractImages.submit=Extraer
fileToPDF.title=Archivo a PDF fileToPDF.title=Archivo a PDF
fileToPDF.header=Convertir cualquier archivo a PDF fileToPDF.header=Convertir cualquier archivo a PDF
fileToPDF.credit=Este servicio usa LibreOffice y Unoconv para la conversión de archivos fileToPDF.credit=Este servicio usa LibreOffice y Unoconv para la conversión de archivos
fileToPDF.supportedFileTypesInfo=Tipos de archivos admitidos fileToPDF.supportedFileTypesInfo=Supported File types
fileToPDF.supportedFileTypes=Los tipos de archivo soportados deben incluir los indicados a continuación; sin embargo, para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice fileToPDF.supportedFileTypes=Los tipos de archivo soportados deben incluir los indicados a continuación; sin embargo, para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice
fileToPDF.submit=Convertir a PDF fileToPDF.submit=Convertir a PDF
@@ -1000,8 +1000,8 @@ pdfToPDFA.header=PDF a PDF/A
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
pdfToPDFA.submit=Convertir pdfToPDFA.submit=Convertir
pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez
pdfToPDFA.outputFormat=Formato de salida pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=El PDF contiene una firma digital. Esto se eliminará en el siguiente paso. pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1103,13 +1103,13 @@ licenses.version=Versión
licenses.license=Licencia licenses.license=Licencia
#survey #survey
survey.nav=Encuesta survey.nav=Survey
survey.title=Encuesta Stirling-PDF survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF no tiene seguimiento, por lo que queremos escuchar a nuestros usuarios para mejorar Stirling-PDF. survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=¡Considere realizar nuestra encuesta! survey.please=Please consider taking our survey!
survey.disabled=(La ventana emergente de la encuesta se desactivará en las siguientes actualizaciones, pero estará disponible al pie de la página.) survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Realizar encuesta survey.button=Take Survey
survey.dontShowAgain=No volver a mostrar survey.dontShowAgain=Don't show again
#error #error
@@ -1124,3 +1124,4 @@ error.showStack=Mostrar seguimiento de pila
error.copyStack=Mostrar seguimiento de pila error.copyStack=Mostrar seguimiento de pila
error.githubSubmit=GitHub - Enviar un ticket error.githubSubmit=GitHub - Enviar un ticket
error.discordSubmit=Discord - Enviar mensaje de soporte error.discordSubmit=Discord - Enviar mensaje de soporte

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Afficher la Stack Trace
error.copyStack=Copier la Stack Trace error.copyStack=Copier la Stack Trace
error.githubSubmit=GitHub - Créer un ticket error.githubSubmit=GitHub - Créer un ticket
error.discordSubmit=Discord - Poster un message de demande dassistance error.discordSubmit=Discord - Poster un message de demande dassistance

File diff suppressed because it is too large Load Diff

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Prikaži Stack Trace
error.copyStack=Kopiraj Stack Trace error.copyStack=Kopiraj Stack Trace
error.githubSubmit=GitHub - Pošaljite ticket error.githubSubmit=GitHub - Pošaljite ticket
error.discordSubmit=Discord - Pošalji objavu podrške error.discordSubmit=Discord - Pošalji objavu podrške

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -706,8 +706,8 @@ removeAnnotations.submit=Rimuovi
#compare #compare
compare.title=Compara compare.title=Compara
compare.header=Compara PDF compare.header=Compara PDF
compare.highlightColor.1=Evidenzia colore 1: compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Evidenzia colore 2: compare.highlightColor.2=Highlight Color 2:
compare.document.1=Documento 1 compare.document.1=Documento 1
compare.document.2=Documento 2 compare.document.2=Documento 2
compare.submit=Compara compare.submit=Compara
@@ -1124,3 +1124,4 @@ error.showStack=Mostra traccia dello stack
error.copyStack=Copia traccia dello stack error.copyStack=Copia traccia dello stack
error.githubSubmit=GitHub: invia un ticket error.githubSubmit=GitHub: invia un ticket
error.discordSubmit=Discord: invia post di supporto error.discordSubmit=Discord: invia post di supporto

View File

@@ -1124,3 +1124,4 @@ error.showStack=スタックトレースを表示
error.copyStack=スタックトレースをコピー error.copyStack=スタックトレースをコピー
error.githubSubmit=GitHub - チケットを提出 error.githubSubmit=GitHub - チケットを提出
error.discordSubmit=Discord - サポート投稿を提出 error.discordSubmit=Discord - サポート投稿を提出

View File

@@ -1124,3 +1124,4 @@ error.showStack=스택 추적 보기
error.copyStack=스택 추적 복사 error.copyStack=스택 추적 복사
error.githubSubmit=GitHub - 티켓 제출 error.githubSubmit=GitHub - 티켓 제출
error.discordSubmit=Discord - 문의 게시 error.discordSubmit=Discord - 문의 게시

View File

@@ -1124,3 +1124,4 @@ error.showStack=Geeft tracering weer
error.copyStack=Kopieer tracering error.copyStack=Kopieer tracering
error.githubSubmit=GitHub - Dien een ticket in error.githubSubmit=GitHub - Dien een ticket in
error.discordSubmit=Discord - Maak een support post error.discordSubmit=Discord - Maak een support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Vis stakksporing
error.copyStack=Kopier stakksporing error.copyStack=Kopier stakksporing
error.githubSubmit=GitHub - Send inn en billett error.githubSubmit=GitHub - Send inn en billett
error.discordSubmit=Discord - Send inn støtteinnlegg error.discordSubmit=Discord - Send inn støtteinnlegg

View File

@@ -1124,3 +1124,4 @@ error.showStack=Pokaż Stack Trace
error.copyStack=Kopiuj Stack Trace error.copyStack=Kopiuj Stack Trace
error.githubSubmit=GitHub - wyślij zgłoszenie error.githubSubmit=GitHub - wyślij zgłoszenie
error.discordSubmit=Discord - wyślij posta z prośbą o pomoc error.discordSubmit=Discord - wyślij posta z prośbą o pomoc

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Показать стек вызовов
error.copyStack=Скопировать стек вызовов error.copyStack=Скопировать стек вызовов
error.githubSubmit=GitHub - Отправить заявку error.githubSubmit=GitHub - Отправить заявку
error.discordSubmit=Discord - Отправить запрос в поддержку error.discordSubmit=Discord - Отправить запрос в поддержку

View File

@@ -1124,3 +1124,4 @@ error.showStack=Zobraziť sledovanie zásobníka
error.copyStack=Kopírovať sledovanie zásobníka error.copyStack=Kopírovať sledovanie zásobníka
error.githubSubmit=GitHub - Podajte tiket error.githubSubmit=GitHub - Podajte tiket
error.discordSubmit=Discord - Podajte príspevok na podporu error.discordSubmit=Discord - Podajte príspevok na podporu

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

View File

@@ -1124,3 +1124,4 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post error.discordSubmit=Discord - Submit Support post

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,7 @@ userNotFoundMessage=Kullanıcı bulunamadı.
incorrectPasswordMessage=Mevcut şifre yanlış. incorrectPasswordMessage=Mevcut şifre yanlış.
usernameExistsMessage=Yeni Kullanıcı Adı zaten var. usernameExistsMessage=Yeni Kullanıcı Adı zaten var.
invalidUsernameMessage=Geçersiz kullanıcı adı, kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır. invalidUsernameMessage=Geçersiz kullanıcı adı, kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır.
confirmPasswordErrorMessage=Yeni Şifre ve Yeni Şifreyi Onayla eşleşmelidir. confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Şu anda oturum açmış olan kullanıcı silinemiyor. deleteCurrentUserMessage=Şu anda oturum açmış olan kullanıcı silinemiyor.
deleteUsernameExistsMessage=Kullanıcı adı mevcut değil ve silinemez. deleteUsernameExistsMessage=Kullanıcı adı mevcut değil ve silinemez.
downgradeCurrentUserMessage=Mevcut kullanıcının rolü düşürülemiyor downgradeCurrentUserMessage=Mevcut kullanıcının rolü düşürülemiyor
@@ -86,7 +86,7 @@ pipeline.defaultOption=Özel
pipeline.submitButton=Gönder pipeline.submitButton=Gönder
pipeline.help=Çoklu İşlemler Yardım pipeline.help=Çoklu İşlemler Yardım
pipeline.scanHelp=Klasör Tarama Yardımı pipeline.scanHelp=Klasör Tarama Yardımı
pipeline.deletePrompt=Çoklu işlemleri silmek istediğinizden emin misiniz pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -116,7 +116,7 @@ navbar.multiTool=Çoklu Araçlar
navbar.sections.organize=Düzenle navbar.sections.organize=Düzenle
navbar.sections.convertTo=PDF'ye dönüştür navbar.sections.convertTo=PDF'ye dönüştür
navbar.sections.convertFrom=PDF'den dönüştür navbar.sections.convertFrom=PDF'den dönüştür
navbar.sections.security=Oturum ve Güvenlik navbar.sections.security=Oturum & Güvenlik
navbar.sections.advance=Gelişmiş navbar.sections.advance=Gelişmiş
navbar.sections.edit=Görüntüle ve Düzenle navbar.sections.edit=Görüntüle ve Düzenle
@@ -175,8 +175,8 @@ adminUserSettings.header=Yönetici Kullanıcı Kontrol Ayarları
adminUserSettings.admin=Yönetici adminUserSettings.admin=Yönetici
adminUserSettings.user=Kullanıcı adminUserSettings.user=Kullanıcı
adminUserSettings.addUser=Yeni Kullanıcı Ekle adminUserSettings.addUser=Yeni Kullanıcı Ekle
adminUserSettings.deleteUser=Kullanıcı Sil adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Kullanıcı silinsin mi? adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır. adminUserSettings.usernameInfo=Kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır.
adminUserSettings.roles=Roller adminUserSettings.roles=Roller
adminUserSettings.role=Rol adminUserSettings.role=Rol
@@ -192,21 +192,21 @@ adminUserSettings.changeUserRole=Kullanıcı rolünü değiştir
adminUserSettings.authenticated=Onaylandı adminUserSettings.authenticated=Onaylandı
database.title=Veri Tabanını İçe/Dışa Aktar database.title=Database Import/Export
database.header=Veri Tabanını İçe/Dışa Aktar database.header=Database Import/Export
database.fileName=Dosya Adı database.fileName=File Name
database.creationDate=Oluşturulma Tarihi database.creationDate=Creation Date
database.fileSize=Dosya Boyutu database.fileSize=File Size
database.deleteBackupFile=Yedekleme Dosyasını Sil database.deleteBackupFile=Delete Backup File
database.importBackupFile=Yedekleme Dosyasını İçe Aktar database.importBackupFile=Import Backup File
database.downloadBackupFile=Yedekleme Dosyasını İndir database.downloadBackupFile=Download Backup File
database.info_1=Verileri içe aktarırken, yapının doğru olduğundan emin olmak çok önemlidir. Ne yaptığınızdan emin değilseniz, bir uzmandan tavsiye ve destek alın. Yapıdaki bir hata, uygulamanın tamamen çalıştırılamaması da dahil olmak üzere uygulama sorunlarına neden olabilir. database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application.
database.info_2=Karşıya yüklerken dosya adı önemli değildir. Daha sonra yedekleme_kullanıcısı_yyyyAAggSdd.sql biçiminde yeniden adlandırılacak ve tutarlı bir adlandırma kuralı sağlanacaktır. database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention.
database.submit=Yedeklemeyi İçe Aktar database.submit=Import Backup
database.importIntoDatabaseSuccessed=Veri tabanına başarıyla aktarıldı database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=Dosya bulunamadı database.fileNotFound=File not Found
database.fileNullOrEmpty=Dosya yok veya boş olmamalıdır database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=Dosya İçe Aktarılamadı database.failedImportFile=Failed Import File
############# #############
# HOME-PAGE # # HOME-PAGE #
@@ -353,9 +353,9 @@ home.certSign.title=Sertifika ile İmzala
home.certSign.desc=Bir PDF'i Sertifika/Anahtar (PEM/P12) ile imzalar home.certSign.desc=Bir PDF'i Sertifika/Anahtar (PEM/P12) ile imzalar
certSign.tags=doğrula,PEM,P12,resmi,şifrele certSign.tags=doğrula,PEM,P12,resmi,şifrele
home.removeCertSign.title=Sertifika İmzasını Kaldır home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=PDF'ten sertifika imzasını kaldırır home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=doğrula,PEM,P12,resmi,şifre çöz removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Çoklu-Sayfa Düzeni home.pageLayout.title=Çoklu-Sayfa Düzeni
home.pageLayout.desc=Bir PDF belgesinin çoklu sayfalarını tek bir sayfada birleştirir home.pageLayout.desc=Bir PDF belgesinin çoklu sayfalarını tek bir sayfada birleştirir
@@ -477,12 +477,12 @@ login.locked=Hesabınız kilitlendi.
login.signinTitle=Lütfen giriş yapınız. login.signinTitle=Lütfen giriş yapınız.
login.ssoSignIn=Tek Oturum Açma ile Giriş Yap login.ssoSignIn=Tek Oturum Açma ile Giriş Yap
login.oauth2AutoCreateDisabled=OAUTH2 Otomatik Oluşturma Kullanıcı Devre Dışı Bırakıldı login.oauth2AutoCreateDisabled=OAUTH2 Otomatik Oluşturma Kullanıcı Devre Dışı Bırakıldı
login.oauth2RequestNotFound=Yetkilendirme isteği bulunamadı login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Geçersiz Kullanıcı Bilgisi Yanıtı login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Geçersiz İstek login.oauth2invalidRequest=Invalid Request
login.oauth2AccessDenied=Erişim Reddedildi login.oauth2AccessDenied=Access Denied
login.oauth2InvalidTokenResponse=Geçersiz Belirteç Yanıtı login.oauth2InvalidTokenResponse=Invalid Token Response
login.oauth2InvalidIdToken=Geçersiz Kimlik Belirteci login.oauth2InvalidIdToken=Invalid Id Token
#auto-redact #auto-redact
@@ -681,10 +681,10 @@ certSign.submit=PDF'i İmzala
#removeCertSign #removeCertSign
removeCertSign.title=Sertifika İmzasını Kaldır removeCertSign.title=Remove Certificate Signature
removeCertSign.header=PDF'ten dijital sertifikayı kaldırın removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=PDF dosyası seçin: removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=İmzayı Kaldır removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
@@ -706,8 +706,8 @@ removeAnnotations.submit=Kaldır
#compare #compare
compare.title=Karşılaştır compare.title=Karşılaştır
compare.header=PDF'leri Karşılaştır compare.header=PDF'leri Karşılaştır
compare.highlightColor.1=Vurgu Rengi 1: compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Vurgu Rengi 2: compare.highlightColor.2=Highlight Color 2:
compare.document.1=Belge 1 compare.document.1=Belge 1
compare.document.2=Belge 2 compare.document.2=Belge 2
compare.submit=Karşılaştır compare.submit=Karşılaştır
@@ -744,7 +744,7 @@ repair.submit=Onar
#flatten #flatten
flatten.title=Düzleştir flatten.title=Düzleştir
flatten.header=PDF'leri Düzleştir flatten.header=PDF'leri Düzleştir
flatten.flattenOnlyForms=Yalnızca formları düzleştir flatten.flattenOnlyForms=Flatten only forms
flatten.submit=Düzleştir flatten.submit=Düzleştir
@@ -822,7 +822,7 @@ merge.title=Birleştir
merge.header=Çoklu PDF'leri Birleştir (2+) merge.header=Çoklu PDF'leri Birleştir (2+)
merge.sortByName=İsme göre sırala merge.sortByName=İsme göre sırala
merge.sortByDate=Tarihe göre sırala merge.sortByDate=Tarihe göre sırala
merge.removeCertSign=Birleştirilen dosyadaki dijital imza kaldırılsın mı? merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Birleştir merge.submit=Birleştir
@@ -840,7 +840,7 @@ pdfOrganiser.mode.6=Tek-Çift Ayrımı
pdfOrganiser.mode.7=İlk Önce Kaldır pdfOrganiser.mode.7=İlk Önce Kaldır
pdfOrganiser.mode.8=Sonuncuyu Kaldır pdfOrganiser.mode.8=Sonuncuyu Kaldır
pdfOrganiser.mode.9=İlk ve Sonu Kaldır pdfOrganiser.mode.9=İlk ve Sonu Kaldır
pdfOrganiser.mode.10=Tek-Çift Birleştirme pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(örn. 1,3,2 veya 4-8,2,10-12 veya 2n-1) pdfOrganiser.placeholder=(örn. 1,3,2 veya 4-8,2,10-12 veya 2n-1)
@@ -1099,17 +1099,17 @@ licenses.nav=Lisanslar
licenses.title=3. Taraf Lisansları licenses.title=3. Taraf Lisansları
licenses.header=3. Taraf Lisansları licenses.header=3. Taraf Lisansları
licenses.module=Modül licenses.module=Modül
licenses.version=Sürüm licenses.version=Versiyon
licenses.license=Lisans licenses.license=Lisans
#survey #survey
survey.nav=Anket survey.nav=Survey
survey.title=Stirling-PDF Anketi survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF'te izleme yok, bu yüzden Stirling-PDF'i iyileştirmek için kullanıcılarımızdan geri bildirim almak istiyoruz! survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Lütfen anketimize katılmayı düşünün! survey.please=Please consider taking our survey!
survey.disabled=(Anket açılır penceresi sonraki güncellemelerde devre dışı bırakılacak ancak sayfanın alt kısmında yer alacaktır) survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Ankete Katıl survey.button=Take Survey
survey.dontShowAgain=Tekrar gösterme survey.dontShowAgain=Don't show again
#error #error
@@ -1124,3 +1124,4 @@ error.showStack=Yığın İzlemesini Göster
error.copyStack=Yığın İzini Kopyala error.copyStack=Yığın İzini Kopyala
error.githubSubmit=GitHub - Hata gönderin error.githubSubmit=GitHub - Hata gönderin
error.discordSubmit=Discord - Destek gönderisi gönderin error.discordSubmit=Discord - Destek gönderisi gönderin

View File

@@ -1124,3 +1124,4 @@ error.showStack=Показати стек викликів
error.copyStack=Скопіювати стек викликів error.copyStack=Скопіювати стек викликів
error.githubSubmit=GitHub - Надіслати запит error.githubSubmit=GitHub - Надіслати запит
error.discordSubmit=Discord - Надіслати повідомлення підтримки error.discordSubmit=Discord - Надіслати повідомлення підтримки

File diff suppressed because it is too large Load Diff

View File

@@ -192,21 +192,21 @@ adminUserSettings.changeUserRole=更改用户角色
adminUserSettings.authenticated=已验证 adminUserSettings.authenticated=已验证
database.title=数据库 导入/导出 database.title=Database Import/Export
database.header=数据库 导入/导出 database.header=Database Import/Export
database.fileName=文件名 database.fileName=File Name
database.creationDate=创建时间 database.creationDate=Creation Date
database.fileSize=文件大小 database.fileSize=File Size
database.deleteBackupFile=删除备份文件 database.deleteBackupFile=Delete Backup File
database.importBackupFile=导入备份文件 database.importBackupFile=Import Backup File
database.downloadBackupFile=下载备份文件 database.downloadBackupFile=Download Backup File
database.info_1=导入数据时,确保结构正确至关重要。如果您不确定自己在做什么,请寻求专业人士的建议和支持。结构错误会导致应用程序故障,甚至完全无法运行应用程序。 database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application.
database.info_2=上传文件时,文件名并不重要。上传后,文件名将重命名为 backup_user_yyyyMMddHHmm.sql以确保命名规范的一致性。 database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention.
database.submit=导入备份 database.submit=Import Backup
database.importIntoDatabaseSuccessed=导入数据库成功 database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=未找到文件 database.fileNotFound=File not Found
database.fileNullOrEmpty=文件不能为空 database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=导入文件失败 database.failedImportFile=Failed Import File
############# #############
# HOME-PAGE # # HOME-PAGE #
@@ -1124,3 +1124,4 @@ error.showStack=显示堆栈跟踪
error.copyStack=复制堆栈跟踪 error.copyStack=复制堆栈跟踪
error.githubSubmit=GitHub - 提交工单 error.githubSubmit=GitHub - 提交工单
error.discordSubmit=Discord - 提交支持帖子 error.discordSubmit=Discord - 提交支持帖子

View File

@@ -9,7 +9,7 @@ multiPdfPrompt=選擇多個 PDF 檔案
multiPdfDropPrompt=選擇(或拖放)所有需要的 PDF 檔案 multiPdfDropPrompt=選擇(或拖放)所有需要的 PDF 檔案
imgPrompt=選擇圖片 imgPrompt=選擇圖片
genericSubmit=送出 genericSubmit=送出
processTimeWarning=警告:此過程可能長達一分鐘,具體取決於檔案大小 processTimeWarning=警告:此過程可能需要長達一分鐘,具體取決於檔案大小
pageOrderPrompt=自訂頁面順序(輸入以逗號分隔的頁碼或函式,如 2n+1 pageOrderPrompt=自訂頁面順序(輸入以逗號分隔的頁碼或函式,如 2n+1
pageSelectionPrompt=自訂頁面選擇(輸入以逗號分隔的頁碼 1、5、6 或 2n+1 等函數的清單): pageSelectionPrompt=自訂頁面選擇(輸入以逗號分隔的頁碼 1、5、6 或 2n+1 等函數的清單):
goToPage=前往 goToPage=前往
@@ -66,7 +66,7 @@ error=錯誤
oops=哎呀! oops=哎呀!
help=幫助 help=幫助
goHomepage=前往首頁 goHomepage=前往首頁
joinDiscord=加入我們的 Discord 服器 joinDiscord=加入我們的 Discord 服
seeDockerHub=查看 Docker Hub seeDockerHub=查看 Docker Hub
visitGithub=訪問 GitHub 存儲庫 visitGithub=訪問 GitHub 存儲庫
donate=捐贈 donate=捐贈
@@ -108,7 +108,7 @@ pipelineOptions.validateButton=驗證
# NAVBAR # # NAVBAR #
############# #############
navbar.favorite=我的最愛 navbar.favorite=我的最愛
navbar.darkmode=深色模式 navbar.darkmode=暗黑模式
navbar.language=語言 navbar.language=語言
navbar.settings=設定 navbar.settings=設定
navbar.allTools=工具 navbar.allTools=工具
@@ -125,7 +125,7 @@ navbar.sections.edit=檢視與編輯
############# #############
settings.title=設定 settings.title=設定
settings.update=有更新可用 settings.update=有更新可用
settings.updateAvailable=當前版本為 {0}。歡迎更新至最新版 ({1})。。 settings.updateAvailable=當前版本為 {0}。歡迎更新至最新版 ({1})。。
settings.appVersion=應用版本: settings.appVersion=應用版本:
settings.downloadOption.title=選擇下載選項(對於單一檔案非壓縮下載): settings.downloadOption.title=選擇下載選項(對於單一檔案非壓縮下載):
settings.downloadOption.1=在同一視窗中開啟 settings.downloadOption.1=在同一視窗中開啟
@@ -139,8 +139,8 @@ settings.cacheInputs.name=輸入檔案下載
settings.cacheInputs.help=開啟記住先前的輸入,做為日後使用 settings.cacheInputs.help=開啟記住先前的輸入,做為日後使用
changeCreds.title=變更憑證 changeCreds.title=變更憑證
changeCreds.header=更新的帳戶詳細資訊 changeCreds.header=更新的帳戶詳細資訊
changeCreds.changePassword=使用的是預設登錄認證。請輸入新密碼 changeCreds.changePassword=使用的是預設登錄認證。請輸入新密碼
changeCreds.newUsername=新使用者名稱 changeCreds.newUsername=新使用者名稱
changeCreds.oldPassword=目前密碼 changeCreds.oldPassword=目前密碼
changeCreds.newPassword=新密碼 changeCreds.newPassword=新密碼
@@ -161,7 +161,7 @@ account.newPassword=新密碼
account.changePassword=修改密碼 account.changePassword=修改密碼
account.confirmNewPassword=確認新密碼 account.confirmNewPassword=確認新密碼
account.signOut=登出 account.signOut=登出
account.yourApiKey=的 API 金鑰 account.yourApiKey=的 API 金鑰
account.syncTitle=將瀏覽器設定與帳戶同步 account.syncTitle=將瀏覽器設定與帳戶同步
account.settingsCompare=設定比較: account.settingsCompare=設定比較:
account.property=屬性 account.property=屬性
@@ -192,26 +192,26 @@ adminUserSettings.changeUserRole=更改使用者身份
adminUserSettings.authenticated=已驗證 adminUserSettings.authenticated=已驗證
database.title=資料庫匯入/匯出 database.title=Database Import/Export
database.header=資料庫匯入/匯出 database.header=Database Import/Export
database.fileName=檔案名稱 database.fileName=File Name
database.creationDate=建立日期 database.creationDate=Creation Date
database.fileSize=檔案大小 database.fileSize=File Size
database.deleteBackupFile=刪除備份檔案 database.deleteBackupFile=Delete Backup File
database.importBackupFile=匯入備份檔案 database.importBackupFile=Import Backup File
database.downloadBackupFile=下載備份檔案 database.downloadBackupFile=Download Backup File
database.info_1=在匯入資料時,確保正確的結構是至關重要的。如果你不確定自己在做什麼,請尋求專業人士的建議和支持。結構錯誤可能會導致應用程式故障,甚至完全無法運行。 database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application.
database.info_2=上傳時檔案名稱無關緊要。上傳後將重新命名為 backup_user_yyyyMMddHHmm.sql 格式,以確保命名規範一致。 database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention.
database.submit=匯入備份 database.submit=Import Backup
database.importIntoDatabaseSuccessed=成功匯入資料庫 database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=檔案未找到 database.fileNotFound=File not Found
database.fileNullOrEmpty=檔案不能為空或空白 database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=匯入檔案失敗 database.failedImportFile=Failed Import File
############# #############
# HOME-PAGE # # HOME-PAGE #
############# #############
home.desc=的本地主機一站式 PDF 需求解決方案。 home.desc=的本地主機一站式 PDF 需求解決方案。
home.searchBar=搜尋功能... home.searchBar=搜尋功能...
@@ -232,7 +232,7 @@ home.split.desc=將 PDF 分割為多個文件
split.tags=頁面操作,劃分,多頁,剪下,伺服器端 split.tags=頁面操作,劃分,多頁,剪下,伺服器端
home.rotate.title=旋轉 home.rotate.title=旋轉
home.rotate.desc=輕鬆旋轉的 PDF。 home.rotate.desc=輕鬆旋轉的 PDF。
rotate.tags=伺服器端 rotate.tags=伺服器端
@@ -254,24 +254,24 @@ home.addImage.desc=在 PDF 的指定位置新增圖片
addImage.tags=img,jpg,圖片,照片 addImage.tags=img,jpg,圖片,照片
home.watermark.title=新增浮水印 home.watermark.title=新增浮水印
home.watermark.desc=的 PDF 檔案中新增自訂浮水印。 home.watermark.desc=的 PDF 檔案中新增自訂浮水印。
watermark.tags=文字,重複,標籤,自有,版權,商標,img,jpg,圖片,照片 watermark.tags=文字,重複,標籤,自有,版權,商標,img,jpg,圖片,照片
home.permissions.title=修改權限 home.permissions.title=修改權限
home.permissions.desc=修改的 PDF 檔案權限 home.permissions.desc=修改的 PDF 檔案權限
permissions.tags=讀取,寫入,編輯,列印 permissions.tags=讀取,寫入,編輯,列印
home.removePages.title=移除 home.removePages.title=移除
home.removePages.desc=的 PDF 檔案中刪除不需要的頁面。 home.removePages.desc=的 PDF 檔案中刪除不需要的頁面。
removePages.tags=移除頁面,刪除頁面 removePages.tags=移除頁面,刪除頁面
home.addPassword.title=新增密碼 home.addPassword.title=新增密碼
home.addPassword.desc=用密碼加密的 PDF 檔案。 home.addPassword.desc=用密碼加密的 PDF 檔案。
addPassword.tags=安全,安全性 addPassword.tags=安全,安全性
home.removePassword.title=移除密碼 home.removePassword.title=移除密碼
home.removePassword.desc=的 PDF 檔案中移除密碼保護。 home.removePassword.desc=的 PDF 檔案中移除密碼保護。
removePassword.tags=安全,解密,安全性,取消密碼,刪除密碼 removePassword.tags=安全,解密,安全性,取消密碼,刪除密碼
home.compressPdfs.title=壓縮 home.compressPdfs.title=壓縮
@@ -473,7 +473,7 @@ login.header=登入
login.signin=登入 login.signin=登入
login.rememberme=記住我 login.rememberme=記住我
login.invalid=使用者名稱或密碼無效。 login.invalid=使用者名稱或密碼無效。
login.locked=的帳戶已被鎖定。 login.locked=的帳戶已被鎖定。
login.signinTitle=請登入 login.signinTitle=請登入
login.ssoSignIn=透過織網單一簽入 login.ssoSignIn=透過織網單一簽入
login.oauth2AutoCreateDisabled=OAuth 2.0 自動建立使用者已停用 login.oauth2AutoCreateDisabled=OAuth 2.0 自動建立使用者已停用
@@ -664,15 +664,15 @@ scalePages.submit=送出
#certSign #certSign
certSign.title=憑證簽章 certSign.title=憑證簽章
certSign.header=使用的憑證簽章(進行中) certSign.header=使用的憑證簽章(進行中)
certSign.selectPDF=選擇要簽章的 PDF 檔案: certSign.selectPDF=選擇要簽章的 PDF 檔案:
certSign.jksNote=注意:如果的證書類型未在下面列出,請使用 keytool 命令行工具將其轉換為 Java Keystore .jks 檔。 然後,選擇下面的 .jks 文件選項。 certSign.jksNote=注意:如果的證書類型未在下面列出,請使用 keytool 命令行工具將其轉換為 Java Keystore .jks 檔。 然後,選擇下面的 .jks 文件選項。
certSign.selectKey=選擇的私鑰文件PKCS#8 格式,可能是 .pem 或 .der certSign.selectKey=選擇的私鑰文件PKCS#8 格式,可能是 .pem 或 .der
certSign.selectCert=選擇的憑證文件X.509 格式,可能是 .pem 或 .der certSign.selectCert=選擇的憑證文件X.509 格式,可能是 .pem 或 .der
certSign.selectP12=選擇的 PKCS#12 金鑰庫文件(.p12 或 .pfx可選如果提供它應包含的私鑰和憑證): certSign.selectP12=選擇的 PKCS#12 金鑰庫文件(.p12 或 .pfx可選如果提供它應包含的私鑰和憑證):
certSign.selectJKS=選擇你的 Java Keystore 檔 .jks 或 .keystore certSign.selectJKS=選擇你的 Java Keystore 檔 .jks 或 .keystore
certSign.certType=憑證類型 certSign.certType=憑證類型
certSign.password=輸入的金鑰庫或私鑰密碼(如果有): certSign.password=輸入的金鑰庫或私鑰密碼(如果有):
certSign.showSig=顯示簽章 certSign.showSig=顯示簽章
certSign.reason=原因 certSign.reason=原因
certSign.location=位置 certSign.location=位置
@@ -871,7 +871,7 @@ rotate.submit=旋轉
#split-pdfs #split-pdfs
split.title=分割 PDF split.title=分割 PDF
split.header=分割 PDF split.header=分割 PDF
split.desc.1=選擇的數字是希望進行分割的頁碼 split.desc.1=選擇的數字是希望進行分割的頁碼
split.desc.2=因此,選擇 1,3,7-9 將會將一個 10 頁的文件分割為 6 個單獨的 PDF包括 split.desc.2=因此,選擇 1,3,7-9 將會將一個 10 頁的文件分割為 6 個單獨的 PDF包括
split.desc.3=文件 #1頁面 1 split.desc.3=文件 #1頁面 1
split.desc.4=文件 #2頁面 2 和 3 split.desc.4=文件 #2頁面 2 和 3
@@ -978,7 +978,7 @@ removePassword.submit=移除
#changeMetadata #changeMetadata
changeMetadata.title=標題: changeMetadata.title=標題:
changeMetadata.header=變更中繼資料 changeMetadata.header=變更中繼資料
changeMetadata.selectText.1=請編輯希望變更的變數 changeMetadata.selectText.1=請編輯希望變更的變數
changeMetadata.selectText.2=刪除所有中繼資料 changeMetadata.selectText.2=刪除所有中繼資料
changeMetadata.selectText.3=顯示自訂中繼資料: changeMetadata.selectText.3=顯示自訂中繼資料:
changeMetadata.author=作者: changeMetadata.author=作者:
@@ -1103,13 +1103,13 @@ licenses.version=版本
licenses.license=許可證 licenses.license=許可證
#survey #survey
survey.nav=問卷調查 survey.nav=Survey
survey.title=Stirling-PDF 問卷調查 survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF 沒有追蹤功能,所以我們希望聽取用戶的意見來改進 Stirling-PDF survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=請考慮參加我們的問卷調查! survey.please=Please consider taking our survey!
survey.disabled=(問卷調查彈出窗口將在後續更新中停用,但仍可在頁腳處使用) survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=參加問卷調查 survey.button=Take Survey
survey.dontShowAgain=不要再次顯示 survey.dontShowAgain=Don't show again
#error #error
@@ -1124,3 +1124,4 @@ error.showStack=顯示堆疊追蹤
error.copyStack=複製堆疊追蹤 error.copyStack=複製堆疊追蹤
error.githubSubmit=GitHub - 提交工單 error.githubSubmit=GitHub - 提交工單
error.discordSubmit=Discord - 提交支援帖子 error.discordSubmit=Discord - 提交支援帖子

View File

@@ -906,7 +906,7 @@
{ {
"moduleName": "org.springframework.boot:spring-boot-devtools", "moduleName": "org.springframework.boot:spring-boot-devtools",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
@@ -920,7 +920,7 @@
{ {
"moduleName": "org.springframework.boot:spring-boot-starter-actuator", "moduleName": "org.springframework.boot:spring-boot-starter-actuator",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
@@ -934,7 +934,7 @@
{ {
"moduleName": "org.springframework.boot:spring-boot-starter-data-jpa", "moduleName": "org.springframework.boot:spring-boot-starter-data-jpa",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
@@ -948,7 +948,7 @@
{ {
"moduleName": "org.springframework.boot:spring-boot-starter-jetty", "moduleName": "org.springframework.boot:spring-boot-starter-jetty",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
@@ -969,28 +969,28 @@
{ {
"moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client", "moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
{ {
"moduleName": "org.springframework.boot:spring-boot-starter-security", "moduleName": "org.springframework.boot:spring-boot-starter-security",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
{ {
"moduleName": "org.springframework.boot:spring-boot-starter-thymeleaf", "moduleName": "org.springframework.boot:spring-boot-starter-thymeleaf",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
{ {
"moduleName": "org.springframework.boot:spring-boot-starter-web", "moduleName": "org.springframework.boot:spring-boot-starter-web",
"moduleUrl": "https://spring.io/projects/spring-boot", "moduleUrl": "https://spring.io/projects/spring-boot",
"moduleVersion": "3.3.2", "moduleVersion": "3.3.0",
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },

View File

@@ -25,22 +25,4 @@
user-select: none; user-select: none;
top: 0px; top: 0px;
left: 0; left: 0;
transform-origin: center center;
}
.rotate-handle {
width: 10px;
height: 10px;
background: blue;
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
cursor: pointer;
}
.rotate-button {
background-color: rgba(13, 110, 253, 0.1);
border: none;
cursor: pointer;
padding: 5px;
margin: 2px;
} }

View File

@@ -36,22 +36,4 @@ select#font-select option {
user-select: none; user-select: none;
top: 0px; top: 0px;
left: 0; left: 0;
transform-origin: center center;
}
.rotate-handle {
width: 10px;
height: 10px;
background: blue;
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
cursor: pointer;
}
.rotate-button {
background-color: rgba(13, 110, 253, 0.1);
border: none;
cursor: pointer;
padding: 5px;
margin: 2px;
} }

View File

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-dk" viewBox="0 0 640 480">
<path fill="#c8102e" d="M0 0h640.1v480H0z"/>
<path fill="#fff" d="M205.7 0h68.6v480h-68.6z"/>
<path fill="#fff" d="M0 205.7h640.1v68.6H0z"/>
</svg>

Before

Width:  |  Height:  |  Size: 236 B

View File

@@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ie" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h640v480H0z"/>
<path fill="#009A49" d="M0 0h213.3v480H0z"/>
<path fill="#FF7900" d="M426.7 0H640v480H426.7z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 289 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 600"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#a51931" d="M0 0h900v600H0z"/><path fill="#fff" d="M0 120h900v360H0z"/><path fill="#241d4f" d="M0 240h900v120H0z"/></g></svg>

Before

Width:  |  Height:  |  Size: 241 B

View File

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-vn" viewBox="0 0 640 480">
<defs>
<clipPath id="vn-a">
<path fill-opacity=".7" d="M-85.3 0h682.6v512H-85.3z"/>
</clipPath>
</defs>
<g fill-rule="evenodd" clip-path="url(#vn-a)" transform="translate(80)scale(.9375)">
<path fill="#da251d" d="M-128 0h768v512h-768z"/>
<path fill="#ff0" d="M349.6 381 260 314.3l-89 67.3L204 272l-89-67.7 110.1-1 34.2-109.4L294 203l110.1.1-88.5 68.4 33.9 109.6z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 490 B

View File

@@ -12,7 +12,7 @@ $(document).ready(function () {
event.preventDefault(); event.preventDefault();
firstErrorOccurred = false; firstErrorOccurred = false;
const url = this.action; const url = this.action;
const files = $("#fileInput-input")[0].files; var files = $("#fileInput-input")[0].files;
const formData = new FormData(this); const formData = new FormData(this);
// Remove empty file entries // Remove empty file entries
@@ -36,6 +36,17 @@ $(document).ready(function () {
}, 5000); }, 5000);
try { try {
if (!url.includes("remove-password")) {
// Check if any PDF files are encrypted and handle decryption if necessary
const decryptedFiles = await checkAndDecryptFiles(url ,files);
files = decryptedFiles
// Append decrypted files to formData
decryptedFiles.forEach((file, index) => {
formData.set(`fileInput`, file);
});
}
if (remoteCall === true) { if (remoteCall === true) {
if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) { if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
await submitMultiPdfForm(url, files); await submitMultiPdfForm(url, files);
@@ -72,6 +83,97 @@ $(document).ready(function () {
}); });
}); });
async function checkAndDecryptFiles(url, files) {
const decryptedFiles = [];
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
// Extract the base URL
const baseUrl = new URL(url);
let removePasswordUrl = `${baseUrl.origin}`;
// Check if there's a path before /api/
const apiIndex = baseUrl.pathname.indexOf('/api/');
if (apiIndex > 0) {
removePasswordUrl += baseUrl.pathname.substring(0, apiIndex);
}
// Append the new endpoint
removePasswordUrl += '/api/v1/security/remove-password';
console.log(`Remove password URL: ${removePasswordUrl}`);
for (const file of files) {
console.log(`Processing file: ${file.name}`);
if (file.type !== 'application/pdf') {
console.log(`Skipping non-PDF file: ${file.name}`);
decryptedFiles.push(file);
continue;
}
try {
const arrayBuffer = await file.arrayBuffer();
const loadingTask = pdfjsLib.getDocument({ data: arrayBuffer });
console.log(`Attempting to load PDF: ${file.name}`);
const pdf = await loadingTask.promise;
console.log(`File is not encrypted: ${file.name}`);
decryptedFiles.push(file); // If no error, file is not encrypted
} catch (error) {
if (error.name === 'PasswordException' && error.code === 1) {
console.log(`PDF requires password: ${file.name}`, error);
console.log(`Attempting to remove password from PDF: ${file.name} with password.`);
const password = prompt(`This PDF (${file.name}) is encrypted. Please enter the password:`);
if (!password) {
console.error(`No password provided for encrypted PDF: ${file.name}`);
showErrorBanner(`No password provided for encrypted PDF: ${file.name}`, 'Please enter a valid password.');
throw error;
}
try {
// Prepare FormData for the decryption request
const formData = new FormData();
formData.append('fileInput', file);
formData.append('password', password);
// Use handleSingleDownload to send the request
const decryptionResult = await fetch(removePasswordUrl, { method: "POST", body: formData });
if (decryptionResult && decryptionResult.blob) {
const decryptedBlob = await decryptionResult.blob();
const decryptedFile = new File([decryptedBlob], file.name, { type: 'application/pdf' });
/* // Create a link element to download the file
const link = document.createElement('a');
link.href = URL.createObjectURL(decryptedBlob);
link.download = 'test.pdf';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
*/
decryptedFiles.push(decryptedFile);
console.log(`Successfully decrypted PDF: ${file.name}`);
} else {
throw new Error('Decryption failed: No valid response from server');
}
} catch (decryptError) {
console.error(`Failed to decrypt PDF: ${file.name}`, decryptError);
showErrorBanner(`Failed to decrypt PDF: ${file.name}`, 'Incorrect password or unsupported encryption.');
throw decryptError;
}
} else {
console.log(`Error loading PDF: ${file.name}`, error);
throw error;
}
}
}
return decryptedFiles;
}
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) { async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
try { try {
const response = await fetch(url, { method: "POST", body: formData }); const response = await fetch(url, { method: "POST", body: formData });

View File

@@ -18,7 +18,7 @@ const DraggableUtils = {
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0) const y = (parseFloat(target.getAttribute("data-bs-y")) || 0)
+ event.dy; + event.dy;
target.style.transform = `translate(${x}px, ${y}px) rotate(${target.getAttribute("data-rotation") || 0}deg)`; target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute("data-bs-x", x); target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y); target.setAttribute("data-bs-y", y);
@@ -61,7 +61,7 @@ const DraggableUtils = {
x += event.deltaRect.left; x += event.deltaRect.left;
y += event.deltaRect.top; y += event.deltaRect.top;
target.style.transform = `translate(${x}px, ${y}px) rotate(${target.getAttribute("data-rotation") || 0}deg)`; target.style.transform = "translate(" + x + "px," + y + "px)";
target.setAttribute("data-bs-x", x); target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y); target.setAttribute("data-bs-y", y);
@@ -78,17 +78,6 @@ const DraggableUtils = {
}), }),
], ],
inertia: true, inertia: true,
})
.gesturable({
listeners: {
move: (event) => {
const target = event.target;
const rotation = (parseFloat(target.getAttribute("data-rotation")) || 0) + event.da;
target.style.transform = `translate(${parseFloat(target.getAttribute("data-bs-x")) || 0}px, ${parseFloat(target.getAttribute("data-bs-y")) || 0}px) rotate(${rotation}deg)`;
target.setAttribute("data-rotation", rotation);
this.onInteraction(target);
}
}
}); });
//Arrow key Support for Add-Image and Sign pages //Arrow key Support for Add-Image and Sign pages
if(window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) { if(window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
@@ -131,7 +120,7 @@ const DraggableUtils = {
} }
// Update position // Update position
target.style.transform = `translate(${x}px, ${y}px) rotate(${target.getAttribute("data-rotation") || 0}deg)`; target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-bs-x', x); target.setAttribute('data-bs-x', x);
target.setAttribute('data-bs-y', y); target.setAttribute('data-bs-y', y);
@@ -151,10 +140,9 @@ const DraggableUtils = {
const x = 0; const x = 0;
const y = 20; const y = 20;
createdCanvas.style.transform = `translate(${x}px, ${y}px) rotate(0deg)`; createdCanvas.style.transform = `translate(${x}px, ${y}px)`;
createdCanvas.setAttribute("data-bs-x", x); createdCanvas.setAttribute("data-bs-x", x);
createdCanvas.setAttribute("data-bs-y", y); createdCanvas.setAttribute("data-bs-y", y);
createdCanvas.setAttribute("data-rotation", 0);
//Click element in order to enable arrow keys //Click element in order to enable arrow keys
createdCanvas.addEventListener('click', () => { createdCanvas.addEventListener('click', () => {
@@ -235,7 +223,6 @@ const DraggableUtils = {
element: el, element: el,
offsetWidth: el.offsetWidth, offsetWidth: el.offsetWidth,
offsetHeight: el.offsetHeight, offsetHeight: el.offsetHeight,
rotation: el.getAttribute("data-rotation") || 0,
}; };
}); });
elements.forEach((el) => this.boxDragContainer.removeChild(el)); elements.forEach((el) => this.boxDragContainer.removeChild(el));
@@ -255,11 +242,7 @@ const DraggableUtils = {
const draggablesData = pagesMap[this.pageIndex]; const draggablesData = pagesMap[this.pageIndex];
if (draggablesData) { if (draggablesData) {
draggablesData.forEach((draggableData) => { draggablesData.forEach((draggableData) => this.boxDragContainer.appendChild(draggableData.element));
const el = draggableData.element;
el.style.transform = `translate(${parseFloat(el.getAttribute("data-bs-x")) || 0}px, ${parseFloat(el.getAttribute("data-bs-y")) || 0}px) rotate(${draggableData.rotation}deg)`;
this.boxDragContainer.appendChild(el);
});
} }
this.documentsMap.set(this.pdfDoc, pagesMap); this.documentsMap.set(this.pdfDoc, pagesMap);
@@ -340,7 +323,6 @@ const DraggableUtils = {
y: parseFloat(transformComponents[1]), y: parseFloat(transformComponents[1]),
width: draggableData.offsetWidth, width: draggableData.offsetWidth,
height: draggableData.offsetHeight, height: draggableData.offsetHeight,
rotation: parseFloat(draggableData.rotation),
}; };
const draggablePositionRelative = { const draggablePositionRelative = {
x: draggablePositionPixels.x / offsetWidth, x: draggablePositionPixels.x / offsetWidth,
@@ -353,7 +335,6 @@ const DraggableUtils = {
y: draggablePositionRelative.y * page.getHeight(), y: draggablePositionRelative.y * page.getHeight(),
width: draggablePositionRelative.width * page.getWidth(), width: draggablePositionRelative.width * page.getWidth(),
height: draggablePositionRelative.height * page.getHeight(), height: draggablePositionRelative.height * page.getHeight(),
rotation: draggablePositionPixels.rotation,
}; };
// draw the image // draw the image
@@ -362,7 +343,6 @@ const DraggableUtils = {
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height, y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
width: draggablePositionPdf.width, width: draggablePositionPdf.width,
height: draggablePositionPdf.height, height: draggablePositionPdf.height,
rotate: PDFLib.degrees(draggablePositionPdf.rotation),
}); });
} }
} }
@@ -370,13 +350,6 @@ const DraggableUtils = {
this.loadPageContents(); this.loadPageContents();
return pdfDocModified; return pdfDocModified;
}, },
rotateElement(element, angle) {
const currentRotation = parseFloat(element.getAttribute("data-rotation")) || 0;
const newRotation = currentRotation + angle;
element.style.transform = `translate(${parseFloat(element.getAttribute("data-bs-x")) || 0}px, ${parseFloat(element.getAttribute("data-bs-y")) || 0}px) rotate(${newRotation}deg)`;
element.setAttribute("data-rotation", newRotation);
},
}; };
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {

View File

@@ -19,7 +19,7 @@
<p th:text="#{error.contactTip}"></p> <p th:text="#{error.contactTip}"></p>
<div id="button-group"> <div id="button-group">
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" class="btn btn-primary" target="_blank" th:text="#{error.github}"></a> <a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" class="btn btn-primary" target="_blank" th:text="#{error.github}"></a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a> <a href="https://discord.gg/HYmhKj45pU" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a>
</div> </div>
<a th:href="@{'/'}" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a> <a th:href="@{'/'}" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a>
</div> </div>

View File

@@ -20,7 +20,7 @@
</div> </div>
<!-- Buttons to submit a ticket on GitHub and join Discord server --> <!-- Buttons to submit a ticket on GitHub and join Discord server -->
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank" th:text="#{error.github}"></a> <a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank" th:text="#{error.github}"></a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank" th:text="#{joinDiscord}"></a> <a href="https://discord.gg/HYmhKj45pU" id="discord-button" target="_blank" th:text="#{joinDiscord}"></a>
</div> </div>
</div> </div>
<script> <script>

View File

@@ -39,7 +39,7 @@
<p th:text="#{error.contactTip}"></p> <p th:text="#{error.contactTip}"></p>
<div id="button-group"> <div id="button-group">
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank" th:text="#{error.githubSubmit}"></a> <a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank" th:text="#{error.githubSubmit}"></a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank" th:text="#{error.discordSubmit}"></a> <a href="https://discord.gg/HYmhKj45pU" id="discord-button" target="_blank" th:text="#{error.discordSubmit}"></a>
</div> </div>
<a th:href="@{'/'}" class="home-button" th:text="#{goHomepage}"></a> <a th:href="@{'/'}" class="home-button" th:text="#{goHomepage}"></a>
<a data-bs-dismiss="modal" class="home-button" th:text="#{close}"></a> <a data-bs-dismiss="modal" class="home-button" th:text="#{close}"></a>

View File

@@ -4,7 +4,6 @@
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ca_CA"> <img th:src="@{'/images/flags/es-ct.svg'}" alt="icon" width="20" height="15"> Català</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ca_CA"> <img th:src="@{'/images/flags/es-ct.svg'}" alt="icon" width="20" height="15"> Català</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_CN"> <img th:src="@{'/images/flags/cn.svg'}" alt="icon" width="20" height="15"> 简体中文</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_CN"> <img th:src="@{'/images/flags/cn.svg'}" alt="icon" width="20" height="15"> 简体中文</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_TW"> <img th:src="@{'/images/flags/tw.svg'}" alt="icon" width="20" height="15"> 繁體中文</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_TW"> <img th:src="@{'/images/flags/tw.svg'}" alt="icon" width="20" height="15"> 繁體中文</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="da_DK"> <img th:src="@{'/images/flags/dk.svg'}" alt="icon" width="20" height="15"> Dansk</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="de_DE"> <img th:src="@{'/images/flags/de.svg'}" alt="icon" width="20" height="15"> Deutsch</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="de_DE"> <img th:src="@{'/images/flags/de.svg'}" alt="icon" width="20" height="15"> Deutsch</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_GB"> <img th:src="@{'/images/flags/gb.svg'}" alt="icon" width="20" height="15"> English (GB)</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_GB"> <img th:src="@{'/images/flags/gb.svg'}" alt="icon" width="20" height="15"> English (GB)</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_US"> <img th:src="@{'/images/flags/us.svg'}" alt="icon" width="20" height="15"> English (US)</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_US"> <img th:src="@{'/images/flags/us.svg'}" alt="icon" width="20" height="15"> English (US)</a>
@@ -12,7 +11,6 @@
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="es_ES"> <img th:src="@{'/images/flags/es.svg'}" alt="icon" width="20" height="15"> Español</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="es_ES"> <img th:src="@{'/images/flags/es.svg'}" alt="icon" width="20" height="15"> Español</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="fr_FR"> <img th:src="@{'/images/flags/fr.svg'}" alt="icon" width="20" height="15"> Français</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="fr_FR"> <img th:src="@{'/images/flags/fr.svg'}" alt="icon" width="20" height="15"> Français</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="id_ID"> <img th:src="@{'/images/flags/id.svg'}" alt="icon" width="20" height="15"> Indonesia</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="id_ID"> <img th:src="@{'/images/flags/id.svg'}" alt="icon" width="20" height="15"> Indonesia</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="id_ID"> <img th:src="@{'/images/flags/ie.svg'}" alt="icon" width="20" height="15"> Irish</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="it_IT"> <img th:src="@{'/images/flags/it.svg'}" alt="icon" width="20" height="15"> Italiano</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="it_IT"> <img th:src="@{'/images/flags/it.svg'}" alt="icon" width="20" height="15"> Italiano</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL"> <img th:src="@{'/images/flags/nl.svg'}" alt="icon" width="20" height="15"> Nederlands</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL"> <img th:src="@{'/images/flags/nl.svg'}" alt="icon" width="20" height="15"> Nederlands</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL"> <img th:src="@{'/images/flags/pl.svg'}" alt="icon" width="20" height="15"> Polski</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL"> <img th:src="@{'/images/flags/pl.svg'}" alt="icon" width="20" height="15"> Polski</a>
@@ -33,6 +31,4 @@
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="cs_CZ"> <img th:src="@{'/images/flags/cz.svg'}" alt="icon" width="20" height="15"> Česky</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="cs_CZ"> <img th:src="@{'/images/flags/cz.svg'}" alt="icon" width="20" height="15"> Česky</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="hr_HR"> <img th:src="@{'/images/flags/hr.svg'}" alt="icon" width="20" height="15"> Hrvatski</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="hr_HR"> <img th:src="@{'/images/flags/hr.svg'}" alt="icon" width="20" height="15"> Hrvatski</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="no_NB"> <img th:src="@{'/images/flags/no.svg'}" alt="icon" width="20" height="15"> Norsk</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="no_NB"> <img th:src="@{'/images/flags/no.svg'}" alt="icon" width="20" height="15"> Norsk</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="th_TH"> <img th:src="@{'/images/flags/th.svg'}" alt="icon" width="20" height="15"> ไทย</a>
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="vi_VN"> <img th:src="@{'/images/flags/vn.svg'}" alt="icon" width="20" height="15"> Tiếng Việt</a>
</th:block> </th:block>

View File

@@ -391,7 +391,7 @@
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" th:title="#{seeDockerHub}"> <a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" th:title="#{seeDockerHub}">
<img th:src="@{'/images/docker.svg'}" alt="docker"> <img th:src="@{'/images/docker.svg'}" alt="docker">
</a> </a>
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" th:title="#{joinDiscord}"> <a href="https://discord.gg/HYmhKj45pU" class="mx-1" role="button" th:title="#{joinDiscord}">
<img th:src="@{'/images/discord.svg'}" alt="discord"> <img th:src="@{'/images/discord.svg'}" alt="discord">
</a> </a>
<a href="https://github.com/sponsors/Frooodle" class="mx-1" role="button" th:title="#{donate}"> <a href="https://github.com/sponsors/Frooodle" class="mx-1" role="button" th:title="#{donate}">

View File

@@ -264,9 +264,8 @@
</div> </div>
<script> <script>
/*
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
const surveyVersion = "1.1"; <!-- const surveyVersion = "1.1";
const modal = new bootstrap.Modal(document.getElementById('surveyModal')); const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
const dontShowAgain = document.getElementById('dontShowAgain'); const dontShowAgain = document.getElementById('dontShowAgain');
const takeSurveyButton = document.getElementById('takeSurvey'); const takeSurveyButton = document.getElementById('takeSurvey');
@@ -294,8 +293,8 @@
if (localStorage.getItem('dontShowSurvey')) { if (localStorage.getItem('dontShowSurvey')) {
modal.hide(); modal.hide();
} } -->
});*/ });
</script> </script>

View File

@@ -83,21 +83,7 @@
</button> </button>
<button class="btn btn-outline-secondary" onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.decrementPage() : DraggableUtils.incrementPage()"> <button class="btn btn-outline-secondary" onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.decrementPage() : DraggableUtils.incrementPage()">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-right" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6-6a.5.5 0 0 1 0-.708z"/> <path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"/>
</svg>
</button>
<button class="btn btn-outline-secondary" onclick="DraggableUtils.rotateElement(DraggableUtils.getLastInteracted(), -90)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.418A6 6 0 1 1 8 2v1z"/>
<path d="M8 1a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0v-4A.5.5 0 0 1 8 1z"/>
<path d="M8 4.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5z"/>
</svg>
</button>
<button class="btn btn-outline-secondary" onclick="DraggableUtils.rotateElement(DraggableUtils.getLastInteracted(), 90)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.418A6 6 0 1 0 8 2v1z"/>
<path d="M8 1a.5.5 0 0 0-.5.5v4a.5.5 0 0 0 1 0v-4A.5.5 0 0 0 8 1z"/>
<path d="M8 4.5a.5.5 0 0 0-.5-.5h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 .5-.5z"/>
</svg> </svg>
</button> </button>
</div> </div>
@@ -117,7 +103,6 @@
link.download = originalFileName + '_addedImage.pdf'; link.download = originalFileName + '_addedImage.pdf';
link.click(); link.click();
}); });
DraggableUtils.init();
</script> </script>
</div> </div>
</div> </div>

View File

@@ -17,9 +17,7 @@
<span class="tool-header-text" th:text="#{autoRedact.header}"></span> <span class="tool-header-text" th:text="#{autoRedact.header}"></span>
</div> </div>
<form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data"> <form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf">
</div>
<div class="mb-3"> <div class="mb-3">
<label for="listOfText" class="form-label" th:text="#{autoRedact.textsToRedactLabel}"></label> <label for="listOfText" class="form-label" th:text="#{autoRedact.textsToRedactLabel}"></label>

View File

@@ -247,20 +247,6 @@
<path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"/> <path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"/>
</svg> </svg>
</button> </button>
<button class="btn btn-outline-secondary" onclick="DraggableUtils.rotateLeft()">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.418A6 6 0 1 1 8 2v1z"/>
<path d="M8 1a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0v-4A.5.5 0 0 1 8 1z"/>
<path d="M8 4.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5z"/>
</svg>
</button>
<button class="btn btn-outline-secondary" onclick="DraggableUtils.rotateRight()">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.418A6 6 0 1 0 8 2v1z"/>
<path d="M8 1a.5.5 0 0 0-.5.5v4a.5.5 0 0 0 1 0v-4A.5.5 0 0 0 8 1z"/>
<path d="M8 4.5a.5.5 0 0 0-.5-.5h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 .5-.5z"/>
</svg>
</button>
</div> </div>
</div> </div>
@@ -279,7 +265,6 @@
link.download = originalFileName + '_signed.pdf'; link.download = originalFileName + '_signed.pdf';
link.click(); link.click();
}); });
DraggableUtils.init();
</script> </script>
</div> </div>
</div> </div>

View File

@@ -13,7 +13,7 @@ public class FileToPdfTest {
@Test @Test
public void testConvertHtmlToPdf() { public void testConvertHtmlToPdf() {
HTMLToPdfRequest request = new HTMLToPdfRequest(); HTMLToPdfRequest request = new HTMLToPdfRequest();
byte[] fileBytes = new byte[0]; // Sample file bytes byte[] fileBytes = new byte[10]; // Sample file bytes
String fileName = "test.html"; // Sample file name String fileName = "test.html"; // Sample file name
boolean htmlFormatsInstalled = true; // Sample boolean value boolean htmlFormatsInstalled = true; // Sample boolean value

View File

@@ -1,11 +1,10 @@
package stirling.software.SPDF; package stirling.software.SPDF.utils;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -15,6 +14,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import stirling.software.SPDF.SPdfApplication;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@@ -43,43 +43,12 @@ public class SPdfApplicationTest {
@Test @Test
public void testMainApplicationStartup() throws IOException, InterruptedException { public void testMainApplicationStartup() throws IOException, InterruptedException {
// Setup mock environment for the main method
Path configPath = Path.of("test/configs");
Path settingsPath = Paths.get("test/configs/settings.yml");
Path customSettingsPath = Paths.get("test/configs/custom_settings.yml");
Path staticPath = Path.of("test/customFiles/static/");
Path templatesPath = Path.of("test/customFiles/templates/");
// Ensure the files do not exist for the test
if (Files.exists(settingsPath)) {
Files.delete(settingsPath);
}
if (Files.exists(customSettingsPath)) {
Files.delete(customSettingsPath);
}
if (Files.exists(staticPath)) {
Files.delete(staticPath);
}
if (Files.exists(templatesPath)) {
Files.delete(templatesPath);
}
// Ensure the directories are created for testing
Files.createDirectories(configPath);
Files.createDirectories(staticPath);
Files.createDirectories(templatesPath);
Files.createFile(settingsPath);
Files.createFile(customSettingsPath);
// Run the main method // Run the main method
SPdfApplication.main(new String[]{}); SPdfApplication.main(new String[]{});
// Verify that the directories were created // Verify that the directories were created
assertTrue(Files.exists(settingsPath)); assertTrue(Files.exists(Path.of("customFiles/static/")));
assertTrue(Files.exists(customSettingsPath)); assertTrue(Files.exists(Path.of("customFiles/templates/")));
assertTrue(Files.exists(staticPath));
assertTrue(Files.exists(templatesPath));
} }
@Test @Test

View File

@@ -88,9 +88,6 @@ main() {
passed_tests+=("Stirling-PDF-Regression") passed_tests+=("Stirling-PDF-Regression")
else else
failed_tests+=("Stirling-PDF-Regression") failed_tests+=("Stirling-PDF-Regression")
echo "Printing docker logs of failed regression"
docker logs "Stirling-PDF"
echo "Printed docker logs of failed regression"
fi fi
cd .. cd ..
fi fi