Compare commits

..

42 Commits

Author SHA1 Message Date
Anthony Stirling
ce0f199981 Update add-image.html 2024-08-03 13:07:21 +01:00
Anthony Stirling
4e4a71b56d Update sign.html 2024-08-03 13:07:07 +01:00
Anthony Stirling
5004d2df37 Update add-image.css 2024-08-03 13:06:52 +01:00
Anthony Stirling
d57b36a61a Update sign.css 2024-08-03 13:06:35 +01:00
Anthony Stirling
a35d3223ea Update draggable-utils.js 2024-08-03 13:06:18 +01:00
Ludy
e6793bd04a Fix: fail JUnit test (#1625) 2024-08-03 12:52:50 +01:00
Anthony Stirling
0f60974a57 Update examples.feature (#1624) 2024-08-03 10:44:17 +01:00
dependabot[bot]
0ed4c16dc0 Bump io.spring.dependency-management from 1.1.5 to 1.1.6 (#1579)
Bumps [io.spring.dependency-management](https://github.com/spring-gradle-plugins/dependency-management-plugin) from 1.1.5 to 1.1.6.
- [Release notes](https://github.com/spring-gradle-plugins/dependency-management-plugin/releases)
- [Commits](https://github.com/spring-gradle-plugins/dependency-management-plugin/compare/v1.1.5...v1.1.6)

---
updated-dependencies:
- dependency-name: io.spring.dependency-management
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-03 10:33:57 +01:00
Manohar Mannam
ea6d4a293e blank pages returns removed pages for verification #1574 (#1619)
separated blank and non-blank pages and created unified ZIP archive

Co-authored-by: mannam <101550345+ManoharMannam@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-08-03 09:30:53 +00:00
Anthony Stirling
191e79da18 Update test.yml (#1623)
* Update test.yml

* Update SPdfApplication.java
2024-08-03 10:29:34 +01:00
Ludy
c54c18b247 Add: Irish and Danish to the table (#1622) 2024-08-03 10:16:26 +01:00
github-actions[bot]
39cbb5e7d9 📝 Update README: Translation Progress Table (#1615)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-08-01 00:10:12 +01:00
LizardWizardGB
3df0474ed2 Danish language (#1606)
* Update languages.html

Added an entry for "Danish".

* Update languages.html

filename of flag was wrong.

* Danish flag svg

* Create messages_da_DK.properties

Initial commit of danish translation.

* Update messages_da_DK.properties

* Update messages_da_DK.properties
2024-07-31 21:25:57 +01:00
congyuluo
9ff2cb63d0 Refactored Identifiers (#1609) 2024-07-31 21:25:48 +01:00
github-actions[bot]
d8087d8c55 📝 Update README: Translation Progress Table (#1613)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-31 21:25:37 +01:00
Aindriú Mac Giolla Eoin
0dfb4d77c0 Added Irish Language (#1607)
Adding Irish Language
2024-07-31 18:17:01 +00:00
Ludy
065f53e577 Optimize Editor and Git Ignore Settings for Improved Consistency and Security (#1611) 2024-07-31 18:49:52 +01:00
github-actions[bot]
c899f605a9 📝 Update README: Translation Progress Table (#1601)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-27 09:11:41 +01:00
DeH40
47de0f84db Update messages_zh_CN.properties (#1599)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-07-27 09:11:16 +01:00
Ludy
543b96c033 Add: Vietnam to the table (#1600)
* Add: Vietnam to the table

* Update labeler-config.yml
2024-07-27 08:37:22 +01:00
github-actions[bot]
c1126e57bd 📝 Update README: Translation Progress Table (#1598)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-26 16:01:23 +01:00
an-777
7c5077006d Update messages_zh_TW.properties: Translate English sentence to Traditional Chinese (#1596)
* Update messages_zh_TW.properties

* fix eof
2024-07-26 13:19:20 +01:00
github-actions[bot]
3e7889cee8 📝 Update README: Translation Progress Table (#1597)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-26 13:06:48 +01:00
Son Tran Lam
281047f42a Translate to Vietnamese (#1591)
* Translate to Vietnamese

* Add translation for Vietnamese

* - Remove  invalid properties and duplicated values.
- Add blank lines to align with the original format of en_GB file

* fix eof

* add empty lines to align with the template format. The number of line is equal with the reference en_GB file now

* change some translations to be more natural and easier to understand
2024-07-26 13:01:17 +01:00
github-actions[bot]
07f85ea8b4 📝 Update README: Translation Progress Table (#1587)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-26 13:00:54 +01:00
Jean-Baptiste WITTNER
e07f73dce7 [Helm][K8S] Add rootPath helm (#1593)
* Update of values.yaml to use a new variable to manage the application rootpath

* Use rootPath of values in deployment to manage rootPath and probes
2024-07-24 21:58:04 +01:00
albanobattistella
bfe38c71e8 Update messages_it_IT.properties (#1588) 2024-07-23 20:18:00 +01:00
Clara Bujeda
072090d41b Update of what was missing in messages_es_ES.properties (#1586)
I have translated what was missing from translating so everything would be translated.
2024-07-23 18:51:46 +01:00
Ludy
560936e182 remove new lines and obsolete spaces (#1585) 2024-07-23 16:57:21 +01:00
Ludy
6eb79e65fa minor changes in the DEV tools and more (#1578) 2024-07-22 21:15:10 +01:00
github-actions[bot]
cbe92269f4 Update 3rd Party Licenses (#1572)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-07-20 10:49:09 +01:00
dependabot[bot]
81871a6f10 Bump springBootVersion from 3.3.0 to 3.3.2 (#1570)
Bumps `springBootVersion` from 3.3.0 to 3.3.2.

Updates `org.springframework.boot:spring-boot-starter-web` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-starter-jetty` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-starter-thymeleaf` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-starter-security` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-starter-data-jpa` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-starter-oauth2-client` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-starter-test` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-starter-actuator` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

Updates `org.springframework.boot:spring-boot-devtools` from 3.3.0 to 3.3.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.0...v3.3.2)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-web
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-jetty
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-thymeleaf
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-security
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-data-jpa
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-oauth2-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-test
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-starter-actuator
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework.boot:spring-boot-devtools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-20 10:42:03 +01:00
github-actions[bot]
cf2a7896da 📝 Update README: Translation Progress Table (#1571)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-20 10:41:32 +01:00
Oğuz Ersen
6a3d95ba09 Add missing Turkish translation (#1549)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-07-20 09:15:03 +00:00
Ludy
85ed0c38d1 Adding declaration as repository component & changing primary key type (#1559)
* Adding declaration as repository component & changing primary key type

* Update AuthorityRepository.java

* Update PersistentLoginRepository.java

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-07-20 10:13:49 +01:00
Ludy
6c7dc34640 Add: Label manager (#1560) 2024-07-20 09:57:27 +01:00
Anthony Stirling
ecfdfa5644 Update init-without-ocr.sh 2024-07-20 09:56:39 +01:00
Anthony Stirling
11e279bd12 Remove calibre for now 2024-07-20 09:54:46 +01:00
Anthony Stirling
929f0bbbe5 version bump, multi file fix and disable survey (#1550)
* version bump, multi file fix and disable survey

* example test stuff

* logs

* Update docker-compose-latest.yml

---------

Co-authored-by: a <a>
2024-07-20 09:53:58 +01:00
Ludy
5751b1ac2d adds Thai to the languages ​​table (#1555)
This PR makes #1554 obsolete
2024-07-11 23:35:01 +01:00
taesaeng28
4bf78ffd5d Added support for Thai language (#1551)
* Added support for Thai language

* Correct Thai national flag proportions in SVG

* Remove th_TH from env.LANGS

causer
Failed tests:
Stirling-PDF-Regression
Some tests failed.
Error: Process completed with exit code 1.

* fix incorrect syntax
2024-07-10 18:05:29 +00:00
pixeebot[bot]
b7d37deb85 Refactored to use parameterized SQL APIs (#1545)
Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-07-09 21:18:32 +01:00
98 changed files with 7193 additions and 483 deletions

View File

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

View File

@@ -1,20 +1,49 @@
translation:
Translation:
- changed-files:
- any-glob-to-any-file: 'src/main/resources/messages_*_*.properties'
- any-glob-to-any-file: 'scripts/ignore_translation.toml'
Front End:
- 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:
- any-glob-to-any-file: 'src/main/java/**/*.java'
documentation:
Back End:
- 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:
- 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:
- 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 Normal file
View File

@@ -0,0 +1,93 @@
# 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,4 +1,5 @@
"""check_tabulator.py"""
import argparse
import sys

24
.github/workflows/manage-label.yml vendored Normal file
View File

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

View File

@@ -29,8 +29,8 @@ jobs:
- name: Install Docker Compose
run: |
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 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 chmod +x /usr/local/bin/docker-compose
- name: Set up Python
uses: actions/setup-python@v4

47
.gitignore vendored
View File

@@ -1,5 +1,3 @@
### Eclipse ###
.metadata
bin/
@@ -22,7 +20,6 @@ customFiles/
configs/
watchedFolders/
# Gradle
.gradle
.lock
@@ -119,12 +116,48 @@ watchedFolders/
*.db
/build
/.vscode
/.idea
# Byte-compiled / optimized / DLL files
__pycache__/
*.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
.DS_Store
**/.DS_Store
#cucumber
/cucumber/reports/**
# cucumber
/cucumber/reports/**
# Certs
*.p12
*.pem
*.crt
*.cer
*.der
*.key
*.csr
# cache
.ruff_cache
.mypy_cache
.pytest_cache
.ipynb_checkpoints

53
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"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 \
UMASK=022 \
FAT_DOCKER=true \
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=true
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
# JDK for app
@@ -45,7 +45,6 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
tini \
bash \
curl \
calibre@testing \
shadow \
su-exec \
openssl \

View File

@@ -2,7 +2,7 @@
<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)
[![Discord](https://img.shields.io/discord/1068636748814483718?label=Discord)](https://discord.gg/HYmhKj45pU)
[![Discord](https://img.shields.io/discord/1068636748814483718?label=Discord)](https://discord.gg/Cn8pWhQRxZ)
[![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)
[![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/donate/?hosted_button_id=MN7JPG5G6G3JL)
@@ -165,42 +165,46 @@ Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR
## Supported Languages
Stirling PDF currently supports 32!
Stirling PDF currently supports 38!
| 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 (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| Arabic (العربية) (ar_AR) | ![45%](https://geps.dev/progress/45) |
| 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) |
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) |
| 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) |
| Hungarian (Magyar) (hu_HU) | ![76%](https://geps.dev/progress/76) |
| Bulgarian (Български) (bg_BG) | ![94%](https://geps.dev/progress/94) |
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![78%](https://geps.dev/progress/78) |
| Ukrainian (Українська) (uk_UA) | ![90%](https://geps.dev/progress/90) |
| 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) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![76%](https://geps.dev/progress/76) |
| 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) |
| 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) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![99%](https://geps.dev/progress/99) |
## Contributing (creating issues, translations, fixing bugs, etc.)
@@ -212,7 +216,7 @@ Stirling PDF allows easy customization of the app.
Includes things like
- Custom application name
- Custom slogans, icons, HTML, images CSS etc (via file overrides)
- Custom slogans, icons, HTML, images CSS etc (via file overrides)
There are two options for this, either using the generated settings file ``settings.yml``
This file is located in the ``/configs`` directory and follows standard YAML formatting

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,106 @@
%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

@@ -0,0 +1,106 @@
%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

@@ -0,0 +1,106 @@
%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

@@ -0,0 +1,106 @@
%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

@@ -0,0 +1,106 @@
%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,3 +14,8 @@ def after_scenario(context, scenario):
os.remove('response_file')
if hasattr(context, 'file_name') and os.path.exists(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
@example @general
Feature: API Validation
@positive @password
@@ -92,10 +92,10 @@ Feature: API Validation
| threshold | 90 |
| whitePercent | 99.9 |
When I send the API request to the endpoint "/api/v1/misc/remove-blanks"
Then the response content type should be "application/pdf"
Then the response content type should be "application/octet-stream"
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 PDF should contain 0 pages
And the response status code should be 200
@positive @flatten
Scenario: Flatten PDF
@@ -127,4 +127,4 @@ Feature: API Validation
And the response PDF metadata should include "Title" as "Sample Title"
And the response status code should be 200

View File

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

View File

@@ -94,3 +94,23 @@ Feature: API Validation
| 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,11 +6,14 @@ import io
import random
import string
from reportlab.lib.pagesizes import letter
from reportlab.lib.utils import ImageReader
from reportlab.pdfgen import canvas
import mimetypes
import requests
import zipfile
import shutil
import re
from PIL import Image, ImageDraw
#########
# GIVEN #
@@ -43,8 +46,6 @@ def step_use_example_file(context, filePath, fileInput):
except FileNotFoundError:
raise FileNotFoundError(f"The example file '{filePath}' does not exist.")
@given('the pdf contains {page_count:d} pages')
def step_pdf_contains_pages(context, page_count):
writer = PdfWriter()
@@ -66,8 +67,6 @@ def step_pdf_contains_blank_pages(context, page_count):
context.files[context.param_name].close()
context.files[context.param_name] = open(context.file_name, 'rb')
def create_black_box_image(file_name, size):
can = canvas.Canvas(file_name, pagesize=size)
width, height = size
@@ -76,36 +75,75 @@ def create_black_box_image(file_name, size):
can.showPage()
can.save()
def create_pdf_with_black_boxes(file_name, image_count, page_count):
page_width, page_height = letter
box_size = 72 # 1 inch by 1 inch black box
@given(u'the pdf contains {image_count:d} images of size {width:d}x{height:d} on {page_count:d} pages')
def step_impl(context, image_count, width, height, page_count):
context.param_name = "fileInput"
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)
writer = PdfWriter()
box_counter = 0
for page in range(page_count):
packet = io.BytesIO()
can = canvas.Canvas(packet, pagesize=letter)
can = canvas.Canvas(packet, pagesize=(page_width, page_height))
for i in range(boxes_per_page):
if box_counter >= image_count:
break
x = (i % (page_width // box_size)) * box_size
y = page_height - ((i // (page_width // box_size) + 1) * box_size)
can.setFillColorRGB(0, 0, 0)
can.rect(x, y, box_size, box_size, fill=1)
# Simulating a dynamic image creation (replace this with your actual image creation logic)
# For demonstration, we'll create a simple black image
dummy_image = Image.new('RGB', (image_width, image_height), color='white') # Create a white image
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
can.showPage()
can.save()
packet.seek(0)
new_pdf = PdfReader(packet)
writer.add_page(new_pdf.pages[0])
# Write the PDF to file
with open(file_name, 'wb') as 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')
def step_pdf_contains_images(context, image_count, page_count):
if not hasattr(context, 'param_name'):
@@ -118,7 +156,6 @@ def step_pdf_contains_images(context, image_count, page_count):
context.files[context.param_name].close()
context.files[context.param_name] = open(context.file_name, 'rb')
@given('the pdf contains {page_count:d} pages with random text')
def step_pdf_contains_pages_with_random_text(context, page_count):
buffer = io.BytesIO()
@@ -186,6 +223,21 @@ def save_generated_pdf(context, filename):
# 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}"')
def step_send_api_request(context, endpoint):
url = f"http://localhost:8080{endpoint}"
@@ -278,7 +330,6 @@ def step_save_response_file(context, filename):
f.write(context.response.content)
print(f"Saved response content to {filename}")
@then('the response PDF should contain {page_count:d} pages')
def step_check_response_pdf_page_count(context, page_count):
response_file = io.BytesIO(context.response.content)
@@ -305,3 +356,26 @@ def step_check_response_zip_doc_page_count(context, doc_count, pages_per_doc):
reader = PdfReader(pdf_file)
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}"
@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,7 +22,6 @@ services:
DOCKER_ENABLE_SECURITY: "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"
INSTALL_BOOK_AND_ADVANCED_HTML_OPS: "true"
SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest

View File

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

View File

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

View File

@@ -45,7 +45,6 @@ public class SPdfApplication {
// Check if the BROWSER_OPEN environment variable is set to true
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
if (browserOpen) {
try {
String url = "http://localhost:" + getNonStaticPort();
@@ -79,13 +78,13 @@ public class SPdfApplication {
// custom javs settings file
if (Files.exists(Paths.get("configs/custom_settings.yml"))) {
String existing = propertyFiles.getOrDefault("spring.config.additional-location", "");
if (!existing.isEmpty()) {
existing += ",";
String existingLocation = propertyFiles.getOrDefault("spring.config.additional-location", "");
if (!existingLocation.isEmpty()) {
existingLocation += ",";
}
propertyFiles.put(
"spring.config.additional-location",
existing + "file:configs/custom_settings.yml");
existingLocation + "file:configs/custom_settings.yml");
} else {
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();
if (queryString != null && !queryString.isEmpty()) {
String requestURI = request.getRequestURI();
Map<String, String> parameters = new HashMap<>();
Map<String, String> allowedParameters = new HashMap<>();
// Keep only the allowed parameters
String[] queryParameters = queryString.split("&");
for (String param : queryParameters) {
String[] keyValue = param.split("=");
if (keyValue.length != 2) {
String[] keyValuePair = param.split("=");
if (keyValuePair.length != 2) {
continue;
}
if (ALLOWED_PARAMS.contains(keyValue[0])) {
parameters.put(keyValue[0], keyValue[1]);
if (ALLOWED_PARAMS.contains(keyValuePair[0])) {
allowedParameters.put(keyValuePair[0], keyValuePair[1]);
}
}
// If there are any parameters that are not allowed
if (parameters.size() != queryParameters.length) {
if (allowedParameters.size() != queryParameters.length) {
// Construct new query string
StringBuilder newQueryString = new StringBuilder();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
for (Map.Entry<String, String> entry : allowedParameters.entrySet()) {
if (newQueryString.length() > 0) {
newQueryString.append("&");
}

View File

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

View File

@@ -1,12 +1,12 @@
package stirling.software.SPDF.controller.api.misc;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -17,6 +17,7 @@ import org.apache.pdfbox.text.PDFTextStripper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -50,31 +51,31 @@ public class BlankPageController {
int threshold = request.getThreshold();
float whitePercent = request.getWhitePercent();
PDDocument document = null;
try {
document = Loader.loadPDF(inputFile.getBytes());
try (PDDocument document = Loader.loadPDF(inputFile.getBytes())) {
PDPageTree pages = document.getDocumentCatalog().getPages();
PDFTextStripper textStripper = new PDFTextStripper();
List<Integer> pagesToKeepIndex = new ArrayList<>();
List<PDPage> nonBlankPages = new ArrayList<>();
List<PDPage> blankPages = new ArrayList<>();
int pageIndex = 0;
PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
for (PDPage page : pages) {
logger.info("checking page " + pageIndex);
logger.info("checking page {}", pageIndex);
textStripper.setStartPage(pageIndex + 1);
textStripper.setEndPage(pageIndex + 1);
String pageText = textStripper.getText(document);
boolean hasText = !pageText.trim().isEmpty();
Boolean blank = true;
boolean blank = true;
if (hasText) {
logger.info("page " + pageIndex + " has text, not blank");
logger.info("page {} has text, not blank", pageIndex);
blank = false;
} else {
boolean hasImages = PdfUtils.hasImagesOnPage(page);
if (hasImages) {
logger.info("page " + pageIndex + " has image, running blank detection");
logger.info("page {} has image, running blank detection", pageIndex);
// Render image and save as temp file
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 30);
blank = isBlankImage(image, threshold, whitePercent, threshold);
@@ -82,34 +83,57 @@ public class BlankPageController {
}
if (blank) {
logger.info("Skipping, Image was blank for page #" + pageIndex);
logger.info("Skipping, Image was blank for page #{}", pageIndex);
blankPages.add(page);
} else {
logger.info("page " + pageIndex + " has image which is not blank");
pagesToKeepIndex.add(pageIndex);
logger.info("page {} has image which is not blank", pageIndex);
nonBlankPages.add(page);
}
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();
ZipOutputStream zos = new ZipOutputStream(baos);
String filename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
if (!nonBlankPages.isEmpty()) {
createZipEntry(zos, nonBlankPages, filename + "_nonBlankPages.pdf");
} else {
createZipEntry(zos, blankPages, filename + "_allBlankPages.pdf");
}
return WebResponseUtils.pdfDocToWebResponse(
document,
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_blanksRemoved.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) {
logger.error("exception", e);
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<>();
command.add("gs");
command.add("-sDEVICE=pdfwrite");
command.add("-dCompatibilityLevel=1.4");
command.add("-dCompatibilityLevel=1.5");
switch (optimizeLevel) {
case 1:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -140,7 +140,7 @@ settings.cacheInputs.help=Enable to store previously used inputs for future runs
changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details
changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password
@@ -706,8 +706,8 @@ removeAnnotations.submit=Remove
#compare
compare.title=Compare
compare.header=Compare PDFs
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Compare
@@ -744,7 +744,7 @@ repair.submit=Repair
#flatten
flatten.title=Flatten
flatten.header=Flatten PDF
flatten.flattenOnlyForms=Flatten only forms
flatten.flattenOnlyForms=Flatten only forms
flatten.submit=Flatten
@@ -1124,4 +1124,3 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post

View File

@@ -706,8 +706,8 @@ removeAnnotations.submit=Remove
#compare
compare.title=Compare
compare.header=Compare PDFs
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Compare
@@ -1124,4 +1124,3 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket
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.
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á.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
userAlreadyExistsOAuthMessage=La usuario ya existe como usuario de OAuth2.
userAlreadyExistsWebMessage=El usuario ya existe como usuario web.
error=Error
oops=Ups!
help=Help
help=Ayuda
goHomepage=Ir a la página principal
joinDiscord=Únase a nuestro servidor Discord
seeDockerHub=Ver Docker Hub
@@ -86,7 +86,7 @@ pipeline.defaultOption=Personalizar
pipeline.submitButton=Enviar
pipeline.help=Ayuda de Canalización
pipeline.scanHelp=Ayuda de escaneado de carpetas
pipeline.deletePrompt=Are you sure you want to delete pipeline
pipeline.deletePrompt=¿Estás segura de que quieres eliminar la canalización?
######################
# Pipeline Options #
@@ -107,18 +107,18 @@ pipelineOptions.validateButton=Validar
#############
# NAVBAR #
#############
navbar.favorite=Favorites
navbar.favorite=Favoritos
navbar.darkmode=Modo oscuro
navbar.language=Languages
navbar.language=Idiomas
navbar.settings=Configuración
navbar.allTools=Tools
navbar.multiTool=Multi Tools
navbar.allTools=Herramientas
navbar.multiTool=Multi herramientas
navbar.sections.organize=Organize
navbar.sections.convertTo=Convert to PDF
navbar.sections.convertFrom=Convert from PDF
navbar.sections.security=Sign & Security
navbar.sections.advance=Advanced
navbar.sections.edit=View & Edit
navbar.sections.convertTo=Convertir a PDF
navbar.sections.convertFrom=Convertir desde PDF
navbar.sections.security=Señalización y seguridad
navbar.sections.advance=Avanzado
navbar.sections.edit=Ver y Editar
#############
# SETTINGS #
@@ -175,8 +175,8 @@ adminUserSettings.header=Configuración de control de usuario administrador
adminUserSettings.admin=Administrador
adminUserSettings.user=Usuario
adminUserSettings.addUser=Añadir Nuevo Usuario
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.deleteUser=Eliminar Usuario
adminUserSettings.confirmDeleteUser=¿Se debe eliminar al usuario?
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.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.submit=Guardar Usuario
adminUserSettings.changeUserRole=Cambiar rol de usuario
adminUserSettings.authenticated=Authenticated
adminUserSettings.authenticated=Autenticado
database.title=Database Import/Export
database.header=Database Import/Export
database.fileName=File Name
database.creationDate=Creation Date
database.fileSize=File Size
database.deleteBackupFile=Delete Backup File
database.importBackupFile=Import Backup File
database.downloadBackupFile=Download Backup File
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=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=Import Backup
database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=File not Found
database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=Failed Import File
database.title=Base de Datos Importar/Exportar
database.header=Base de Datos Importar/Exportar
database.fileName=Nombre de Archivo
database.creationDate=Fecha de creación
database.fileSize=Tamaño de archivo
database.deleteBackupFile=Eliminar archivo de copia de seguridad
database.importBackupFile=Importar archivo de copia de seguridad
database.downloadBackupFile=Descargar archivo de copia de seguridad
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_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.submit=Importar Backup
database.importIntoDatabaseSuccessed=Importación a la base de datos ha sido exitosa
database.fileNotFound=Archivo no encontrado
database.fileNullOrEmpty=El archivo no debe ser nulo o vacío.
database.failedImportFile=Archivo de importación fallido
#############
# HOME-PAGE #
@@ -353,8 +353,8 @@ home.certSign.title=Firmar con certificado
home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12)
certSign.tags=autentificar,PEM,P12,oficial,encriptar
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
home.removeCertSign.title=Quitar signo de certificado
home.removeCertSign.desc=Eliminar firma de certificado de PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
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.signinTitle=Por favor, inicie sesión
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.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2AutoCreateDisabled=Usuario de creación automática de OAUTH2 DESACTIVADO
login.oauth2RequestNotFound=Solicitud de autorización no encontrada
login.oauth2InvalidUserInfoResponse=Respuesta de información de usuario no válida
login.oauth2invalidRequest=Invalid Request
login.oauth2AccessDenied=Access Denied
login.oauth2InvalidTokenResponse=Invalid Token Response
login.oauth2InvalidIdToken=Invalid Id Token
login.oauth2InvalidTokenResponse=Respuesta de token no válida
login.oauth2InvalidIdToken=Token de identificación no válido
#auto-redact
@@ -681,10 +681,10 @@ certSign.submit=Firmar PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
removeCertSign.title=Eliminar firma del certificado
removeCertSign.header=Quitar el certificado digital del PDF
removeCertSign.selectPDF=Seleccione un archivo PDF:
removeCertSign.submit=Eliminar firma
#removeBlanks
@@ -706,8 +706,8 @@ removeAnnotations.submit=Eliminar
#compare
compare.title=Comparar
compare.header=Comparar archivos PDF
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.highlightColor.1=Color resaltado 1:
compare.highlightColor.2=Color resaltado 2:
compare.document.1=Documento 1
compare.document.2=Documento 2
compare.submit=Comparar
@@ -744,7 +744,7 @@ repair.submit=Reparar
#flatten
flatten.title=Aplanar
flatten.header=Acoplar archivos PDF
flatten.flattenOnlyForms=Flatten only forms
flatten.flattenOnlyForms=Aplanar sólo formularios
flatten.submit=Aplanar
@@ -792,7 +792,7 @@ extractImages.submit=Extraer
fileToPDF.title=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.supportedFileTypesInfo=Supported File types
fileToPDF.supportedFileTypesInfo=Tipos de archivos admitidos
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
@@ -1000,8 +1000,8 @@ pdfToPDFA.header=PDF a PDF/A
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
pdfToPDFA.submit=Convertir
pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez
pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
pdfToPDFA.outputFormat=Formato de salida
pdfToPDFA.pdfWithDigitalSignature=El PDF contiene una firma digital. Esto se eliminará en el siguiente paso.
#PDFToWord
@@ -1103,13 +1103,13 @@ licenses.version=Versión
licenses.license=Licencia
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
survey.nav=Encuesta
survey.title=Encuesta Stirling-PDF
survey.description=Stirling-PDF no tiene seguimiento, por lo que queremos escuchar a nuestros usuarios para mejorar Stirling-PDF.
survey.please=¡Considere realizar nuestra encuesta!
survey.disabled=(La ventana emergente de la encuesta se desactivará en las siguientes actualizaciones, pero estará disponible al pie de la página.)
survey.button=Realizar encuesta
survey.dontShowAgain=No volver a mostrar
#error
@@ -1124,4 +1124,3 @@ error.showStack=Mostrar seguimiento de pila
error.copyStack=Mostrar seguimiento de pila
error.githubSubmit=GitHub - Enviar un ticket
error.discordSubmit=Discord - Enviar mensaje de soporte

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1124,4 +1124,3 @@ error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket
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ış.
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.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
confirmPasswordErrorMessage=Yeni Şifre ve Yeni Şifreyi Onayla eşleşmelidir.
deleteCurrentUserMessage=Şu anda oturum açmış olan kullanıcı silinemiyor.
deleteUsernameExistsMessage=Kullanıcı adı mevcut değil ve silinemez.
downgradeCurrentUserMessage=Mevcut kullanıcının rolü düşürülemiyor
@@ -86,7 +86,7 @@ pipeline.defaultOption=Özel
pipeline.submitButton=Gönder
pipeline.help=Çoklu İşlemler Yardım
pipeline.scanHelp=Klasör Tarama Yardımı
pipeline.deletePrompt=Are you sure you want to delete pipeline
pipeline.deletePrompt=Çoklu işlemleri silmek istediğinizden emin misiniz
######################
# Pipeline Options #
@@ -116,7 +116,7 @@ navbar.multiTool=Çoklu Araçlar
navbar.sections.organize=Düzenle
navbar.sections.convertTo=PDF'ye dönüştür
navbar.sections.convertFrom=PDF'den dönüştür
navbar.sections.security=Oturum & Güvenlik
navbar.sections.security=Oturum ve Güvenlik
navbar.sections.advance=Gelişmiş
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.user=Kullanıcı
adminUserSettings.addUser=Yeni Kullanıcı Ekle
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.deleteUser=Kullanıcı Sil
adminUserSettings.confirmDeleteUser=Kullanıcı silinsin mi?
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.role=Rol
@@ -192,21 +192,21 @@ adminUserSettings.changeUserRole=Kullanıcı rolünü değiştir
adminUserSettings.authenticated=Onaylandı
database.title=Database Import/Export
database.header=Database Import/Export
database.fileName=File Name
database.creationDate=Creation Date
database.fileSize=File Size
database.deleteBackupFile=Delete Backup File
database.importBackupFile=Import Backup File
database.downloadBackupFile=Download Backup File
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=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=Import Backup
database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=File not Found
database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=Failed Import File
database.title=Veri Tabanını İçe/Dışa Aktar
database.header=Veri Tabanını İçe/Dışa Aktar
database.fileName=Dosya Adı
database.creationDate=Oluşturulma Tarihi
database.fileSize=Dosya Boyutu
database.deleteBackupFile=Yedekleme Dosyasını Sil
database.importBackupFile=Yedekleme Dosyasını İçe Aktar
database.downloadBackupFile=Yedekleme Dosyasını İndir
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_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.submit=Yedeklemeyi İçe Aktar
database.importIntoDatabaseSuccessed=Veri tabanına başarıyla aktarıldı
database.fileNotFound=Dosya bulunamadı
database.fileNullOrEmpty=Dosya yok veya boş olmamalıdır
database.failedImportFile=Dosya İçe Aktarılamadı
#############
# HOME-PAGE #
@@ -353,9 +353,9 @@ home.certSign.title=Sertifika ile İmzala
home.certSign.desc=Bir PDF'i Sertifika/Anahtar (PEM/P12) ile imzalar
certSign.tags=doğrula,PEM,P12,resmi,şifrele
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.removeCertSign.title=Sertifika İmzasını Kaldır
home.removeCertSign.desc=PDF'ten sertifika imzasını kaldırır
removeCertSign.tags=doğrula,PEM,P12,resmi,şifre çöz
home.pageLayout.title=Çoklu-Sayfa Düzeni
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.ssoSignIn=Tek Oturum Açma ile Giriş Yap
login.oauth2AutoCreateDisabled=OAUTH2 Otomatik Oluşturma Kullanıcı Devre Dışı Bırakıldı
login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request
login.oauth2AccessDenied=Access Denied
login.oauth2InvalidTokenResponse=Invalid Token Response
login.oauth2InvalidIdToken=Invalid Id Token
login.oauth2RequestNotFound=Yetkilendirme isteği bulunamadı
login.oauth2InvalidUserInfoResponse=Geçersiz Kullanıcı Bilgisi Yanıtı
login.oauth2invalidRequest=Geçersiz İstek
login.oauth2AccessDenied=Erişim Reddedildi
login.oauth2InvalidTokenResponse=Geçersiz Belirteç Yanıtı
login.oauth2InvalidIdToken=Geçersiz Kimlik Belirteci
#auto-redact
@@ -681,10 +681,10 @@ certSign.submit=PDF'i İmzala
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
removeCertSign.title=Sertifika İmzasını Kaldır
removeCertSign.header=PDF'ten dijital sertifikayı kaldırın
removeCertSign.selectPDF=PDF dosyası seçin:
removeCertSign.submit=İmzayı Kaldır
#removeBlanks
@@ -706,8 +706,8 @@ removeAnnotations.submit=Kaldır
#compare
compare.title=Karşılaştır
compare.header=PDF'leri Karşılaştır
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.highlightColor.1=Vurgu Rengi 1:
compare.highlightColor.2=Vurgu Rengi 2:
compare.document.1=Belge 1
compare.document.2=Belge 2
compare.submit=Karşılaştır
@@ -744,7 +744,7 @@ repair.submit=Onar
#flatten
flatten.title=Düzleştir
flatten.header=PDF'leri Düzleştir
flatten.flattenOnlyForms=Flatten only forms
flatten.flattenOnlyForms=Yalnızca formları 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.sortByName=İsme göre sırala
merge.sortByDate=Tarihe göre sırala
merge.removeCertSign=Remove digital signature in the merged file?
merge.removeCertSign=Birleştirilen dosyadaki dijital imza kaldırılsın mı?
merge.submit=Birleştir
@@ -840,7 +840,7 @@ pdfOrganiser.mode.6=Tek-Çift Ayrımı
pdfOrganiser.mode.7=İlk Önce Kaldır
pdfOrganiser.mode.8=Sonuncuyu Kaldır
pdfOrganiser.mode.9=İlk ve Sonu Kaldır
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.mode.10=Tek-Çift Birleştirme
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.header=3. Taraf Lisansları
licenses.module=Modül
licenses.version=Versiyon
licenses.version=Sürüm
licenses.license=Lisans
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
survey.nav=Anket
survey.title=Stirling-PDF Anketi
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.please=Lütfen anketimize katılmayı düşünün!
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.button=Ankete Katıl
survey.dontShowAgain=Tekrar gösterme
#error
@@ -1124,4 +1124,3 @@ error.showStack=Yığın İzlemesini Göster
error.copyStack=Yığın İzini Kopyala
error.githubSubmit=GitHub - Hata gönderin
error.discordSubmit=Discord - Destek gönderisi gönderin

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -192,21 +192,21 @@ adminUserSettings.changeUserRole=更改用户角色
adminUserSettings.authenticated=已验证
database.title=Database Import/Export
database.header=Database Import/Export
database.fileName=File Name
database.creationDate=Creation Date
database.fileSize=File Size
database.deleteBackupFile=Delete Backup File
database.importBackupFile=Import Backup File
database.downloadBackupFile=Download Backup File
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=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=Import Backup
database.importIntoDatabaseSuccessed=Import into database successed
database.fileNotFound=File not Found
database.fileNullOrEmpty=File must not be null or empty
database.failedImportFile=Failed Import File
database.title=数据库 导入/导出
database.header=数据库 导入/导出
database.fileName=文件名
database.creationDate=创建时间
database.fileSize=文件大小
database.deleteBackupFile=删除备份文件
database.importBackupFile=导入备份文件
database.downloadBackupFile=下载备份文件
database.info_1=导入数据时,确保结构正确至关重要。如果您不确定自己在做什么,请寻求专业人士的建议和支持。结构错误会导致应用程序故障,甚至完全无法运行应用程序。
database.info_2=上传文件时,文件名并不重要。上传后,文件名将重命名为 backup_user_yyyyMMddHHmm.sql以确保命名规范的一致性。
database.submit=导入备份
database.importIntoDatabaseSuccessed=导入数据库成功
database.fileNotFound=未找到文件
database.fileNullOrEmpty=文件不能为空
database.failedImportFile=导入文件失败
#############
# HOME-PAGE #
@@ -1124,4 +1124,3 @@ error.showStack=显示堆栈跟踪
error.copyStack=复制堆栈跟踪
error.githubSubmit=GitHub - 提交工单
error.discordSubmit=Discord - 提交支持帖子

View File

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

View File

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

View File

@@ -25,4 +25,22 @@
user-select: none;
top: 0px;
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,4 +36,22 @@ select#font-select option {
user-select: none;
top: 0px;
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

@@ -0,0 +1,5 @@
<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>

After

Width:  |  Height:  |  Size: 236 B

View File

@@ -0,0 +1,7 @@
<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>

After

Width:  |  Height:  |  Size: 289 B

View File

@@ -0,0 +1 @@
<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>

After

Width:  |  Height:  |  Size: 241 B

View File

@@ -0,0 +1,11 @@
<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>

After

Width:  |  Height:  |  Size: 490 B

View File

@@ -12,7 +12,7 @@ $(document).ready(function () {
event.preventDefault();
firstErrorOccurred = false;
const url = this.action;
var files = $("#fileInput-input")[0].files;
const files = $("#fileInput-input")[0].files;
const formData = new FormData(this);
// Remove empty file entries
@@ -36,17 +36,6 @@ $(document).ready(function () {
}, 5000);
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 (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
await submitMultiPdfForm(url, files);
@@ -56,24 +45,24 @@ $(document).ready(function () {
}
clearTimeout(timeoutId);
$("#submitBtn").text(originalButtonText);
// After process finishes, check for boredWaiting and gameDialog open status
const boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
const gameDialog = document.getElementById('game-container-wrapper');
if (boredWaiting === "enabled" && gameDialog && gameDialog.open) {
// Display a green banner at the bottom of the screen saying "Download complete"
let downloadCompleteText = "Download Complete";
if (window.downloadCompleteText) {
if(window.downloadCompleteText){
downloadCompleteText = window.downloadCompleteText;
}
$("body").append('<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">' + downloadCompleteText + '</div>');
setTimeout(function () {
$("#download-complete-banner").fadeOut("slow", function () {
$("body").append('<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">'+ downloadCompleteText + '</div>');
setTimeout(function() {
$("#download-complete-banner").fadeOut("slow", function() {
$(this).remove(); // Remove the banner after fading out
});
}, 5000); // Banner will fade out after 5 seconds
}
} catch (error) {
clearTimeout(timeoutId);
handleDownloadError(error);
@@ -83,97 +72,6 @@ $(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) {
try {
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)
+ event.dy;
target.style.transform = `translate(${x}px, ${y}px)`;
target.style.transform = `translate(${x}px, ${y}px) rotate(${target.getAttribute("data-rotation") || 0}deg)`;
target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y);
@@ -61,7 +61,7 @@ const DraggableUtils = {
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.transform = "translate(" + x + "px," + y + "px)";
target.style.transform = `translate(${x}px, ${y}px) rotate(${target.getAttribute("data-rotation") || 0}deg)`;
target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y);
@@ -78,6 +78,17 @@ const DraggableUtils = {
}),
],
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
if(window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
@@ -120,7 +131,7 @@ const DraggableUtils = {
}
// Update position
target.style.transform = `translate(${x}px, ${y}px)`;
target.style.transform = `translate(${x}px, ${y}px) rotate(${target.getAttribute("data-rotation") || 0}deg)`;
target.setAttribute('data-bs-x', x);
target.setAttribute('data-bs-y', y);
@@ -140,9 +151,10 @@ const DraggableUtils = {
const x = 0;
const y = 20;
createdCanvas.style.transform = `translate(${x}px, ${y}px)`;
createdCanvas.style.transform = `translate(${x}px, ${y}px) rotate(0deg)`;
createdCanvas.setAttribute("data-bs-x", x);
createdCanvas.setAttribute("data-bs-y", y);
createdCanvas.setAttribute("data-rotation", 0);
//Click element in order to enable arrow keys
createdCanvas.addEventListener('click', () => {
@@ -223,6 +235,7 @@ const DraggableUtils = {
element: el,
offsetWidth: el.offsetWidth,
offsetHeight: el.offsetHeight,
rotation: el.getAttribute("data-rotation") || 0,
};
});
elements.forEach((el) => this.boxDragContainer.removeChild(el));
@@ -242,7 +255,11 @@ const DraggableUtils = {
const draggablesData = pagesMap[this.pageIndex];
if (draggablesData) {
draggablesData.forEach((draggableData) => this.boxDragContainer.appendChild(draggableData.element));
draggablesData.forEach((draggableData) => {
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);
@@ -323,6 +340,7 @@ const DraggableUtils = {
y: parseFloat(transformComponents[1]),
width: draggableData.offsetWidth,
height: draggableData.offsetHeight,
rotation: parseFloat(draggableData.rotation),
};
const draggablePositionRelative = {
x: draggablePositionPixels.x / offsetWidth,
@@ -335,6 +353,7 @@ const DraggableUtils = {
y: draggablePositionRelative.y * page.getHeight(),
width: draggablePositionRelative.width * page.getWidth(),
height: draggablePositionRelative.height * page.getHeight(),
rotation: draggablePositionPixels.rotation,
};
// draw the image
@@ -343,6 +362,7 @@ const DraggableUtils = {
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
width: draggablePositionPdf.width,
height: draggablePositionPdf.height,
rotate: PDFLib.degrees(draggablePositionPdf.rotation),
});
}
}
@@ -350,6 +370,13 @@ const DraggableUtils = {
this.loadPageContents();
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", () => {

View File

@@ -22,7 +22,7 @@
<div class="mb-3">
<label th:text="#{PDFToWord.selectText.1}"></label>
<select class="form-control" name="outputFormat">
<option value="docx">DocX</option>
<option value="docx">DocX</option>
<option value="doc">Doc</option>
<option value="odt">Odt</option>
</select>

View File

@@ -19,7 +19,7 @@
<p th:text="#{error.contactTip}"></p>
<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://discord.gg/HYmhKj45pU" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a>
</div>
<a th:href="@{'/'}" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a>
</div>

View File

@@ -20,7 +20,7 @@
</div>
<!-- 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://discord.gg/HYmhKj45pU" id="discord-button" target="_blank" th:text="#{joinDiscord}"></a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank" th:text="#{joinDiscord}"></a>
</div>
</div>
<script>

View File

@@ -39,7 +39,7 @@
<p th:text="#{error.contactTip}"></p>
<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://discord.gg/HYmhKj45pU" id="discord-button" target="_blank" th:text="#{error.discordSubmit}"></a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank" th:text="#{error.discordSubmit}"></a>
</div>
<a th:href="@{'/'}" class="home-button" th:text="#{goHomepage}"></a>
<a data-bs-dismiss="modal" class="home-button" th:text="#{close}"></a>

View File

@@ -4,6 +4,7 @@
<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_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="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>
@@ -11,6 +12,7 @@
<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="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="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>
@@ -31,4 +33,6 @@
<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="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>

View File

@@ -391,7 +391,7 @@
<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">
</a>
<a href="https://discord.gg/HYmhKj45pU" class="mx-1" role="button" th:title="#{joinDiscord}">
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" th:title="#{joinDiscord}">
<img th:src="@{'/images/discord.svg'}" alt="discord">
</a>
<a href="https://github.com/sponsors/Frooodle" class="mx-1" role="button" th:title="#{donate}">

View File

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

View File

@@ -83,7 +83,21 @@
</button>
<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">
<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 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>
</button>
</div>
@@ -103,6 +117,7 @@
link.download = originalFileName + '_addedImage.pdf';
link.click();
});
DraggableUtils.init();
</script>
</div>
</div>
@@ -111,4 +126,4 @@
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html>
</html>

View File

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

View File

@@ -247,6 +247,20 @@
<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.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>
@@ -265,6 +279,7 @@
link.download = originalFileName + '_signed.pdf';
link.click();
});
DraggableUtils.init();
</script>
</div>
</div>
@@ -273,4 +288,4 @@
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html>
</html>

View File

@@ -1,10 +1,11 @@
package stirling.software.SPDF.utils;
package stirling.software.SPDF;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -14,7 +15,6 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.env.Environment;
import stirling.software.SPDF.SPdfApplication;
import stirling.software.SPDF.model.ApplicationProperties;
@ExtendWith(MockitoExtension.class)
@@ -43,12 +43,43 @@ public class SPdfApplicationTest {
@Test
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
SPdfApplication.main(new String[]{});
// Verify that the directories were created
assertTrue(Files.exists(Path.of("customFiles/static/")));
assertTrue(Files.exists(Path.of("customFiles/templates/")));
assertTrue(Files.exists(settingsPath));
assertTrue(Files.exists(customSettingsPath));
assertTrue(Files.exists(staticPath));
assertTrue(Files.exists(templatesPath));
}
@Test

View File

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

View File

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