Compare commits

...

108 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
github-actions[bot]
2a65fd0825 📝 Update README: Translation Progress Table (#1538)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-07 11:45:50 +01:00
Ludy
422264a288 added non-translatable strings (#1537)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-07-06 21:54:04 +00:00
github-actions[bot]
695fbb0150 📝 Update README: Translation Progress Table (#1536)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-07-06 21:48:53 +00:00
Ludy
a17105e650 Create stale.yml (#1530)
* Create stale.yml

* Update stale.yml
2024-07-06 20:25:38 +00:00
Ludy
32ac38e93f Add missing translations strings (#1535)
* Add missing translations strings

* Update messages_de_DE.properties
2024-07-06 19:48:39 +01:00
Ludy
3c0d2b908f Update messages_de_DE.properties (#1532)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-07-06 18:17:30 +00:00
Ludy
ab62a93a0d Fix labeler 2 (#1534) 2024-07-06 19:15:19 +01:00
Ludy
5189708d25 Fix labeler (#1533)
* Update labeler.yml

* Update labeler.yml
2024-07-06 17:48:06 +01:00
Ludy
19831c050c Add labeler action for pull requests (#1529)
* Automatically label PRs

* Update labeler-config.yml
2024-07-06 15:43:53 +01:00
albanobattistella
e426d99145 Update messages_it_IT.properties (#1527) 2024-07-06 12:27:19 +00:00
Ludy
4088208fc8 adding documentation for database import and export (#1528)
* adding documentation for database import and export

* Update DATABASE.md
2024-07-06 13:24:32 +01:00
albanobattistella
31ce5b1221 Update messages_it_IT.properties (#1526)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-07-05 20:50:22 +01:00
Ludy
be05db22f5 Preparation for Switching to a New Database Version (#1521)
* preparing to switch to a new database version

* add PreAuthorize

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-07-05 20:48:33 +01:00
Ludy
79927416e5 standardize the layout (#1525) 2024-07-04 21:13:03 +00:00
Shawn Johnston
f95ee31bbd Highlight color selection for the Compare PDFs page. (#1515)
* Update compare.html

* Update compare.html

* Conform to text requirements

Changed text in some labels to conform to Thymeleaf format.

* Add GB to th:text for label
2024-07-04 21:11:41 +00:00
Ludy
40042c37f2 [Bugfix] the Manifest Syntax error (#1524)
Fixes the Manifest Syntax error
2024-07-04 21:05:45 +00:00
Ludy
1c90b65bca removes empty list entries (#1523) 2024-07-04 21:04:21 +00:00
Ludy
2971425544 [Bugfix] Prevents the deletion of productive data (#1522)
prevents the deletion of productive data
2024-07-04 22:02:35 +01:00
Prerak Trivedi
a9ee698432 Update README.md (#1518)
removed dead link to a screenshot
2024-07-02 20:29:22 +01:00
github-actions[bot]
15b5d51957 📝 Update README: Translation Progress Table (#1514)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-30 15:11:18 +01:00
eruditus-ginkgo
92893b8d4c Update messages_zh_CN.properties (#1513)
Translate untranslated text to Simplified Chinese;
Standardize Chinese expressions for identical English phrases;
Remove spaces between Chinese and English text for consistency.
2024-06-29 17:45:31 +01:00
Ludy
3a6969cad0 Fix: synchronizing the browser settings to the database #1481 (#1510)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-26 20:48:50 +00:00
Ludy
88e8663d44 Rename from translation_status.toml to ignore_translation.toml and more (#1511) 2024-06-26 21:47:20 +01:00
github-actions[bot]
a2d7490d45 📝 Update README: Translation Progress Table (#1507)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-25 23:21:57 +01:00
Alex
c363a1c4e0 Add some translations and add ignored translations (#1501)
* Create ignore_translation.toml

Added ignored translations

* Update messages_nl_NL.properties

Changed a few translations to be better

* Update ignore_translation.toml

Deleted wrong ignore
2024-06-25 23:16:09 +01:00
Anthony Stirling
9e84836cfe Update pipeline.html 2024-06-22 23:29:36 +01:00
ProvaTeams
c8a2789caf Missing description for Split function in top bar (#1492) 2024-06-20 20:39:59 +01:00
Anthony Stirling
202b996c2b Update README.md 2024-06-19 21:05:56 +01:00
github-actions[bot]
e766a5f583 Update 3rd Party Licenses (#1490)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-06-19 18:37:43 +01:00
dependabot[bot]
c7d18939fc Bump org.springframework:spring-webmvc from 6.1.5 to 6.1.9 (#1462)
Bumps [org.springframework:spring-webmvc](https://github.com/spring-projects/spring-framework) from 6.1.5 to 6.1.9.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.5...v6.1.9)

---
updated-dependencies:
- dependency-name: org.springframework:spring-webmvc
  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>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-19 18:25:09 +01:00
dependabot[bot]
34e198d8e6 Bump com.twelvemonkeys.imageio:imageio-jpeg from 3.10.1 to 3.11.0 (#1486)
Bumps com.twelvemonkeys.imageio:imageio-jpeg from 3.10.1 to 3.11.0.

---
updated-dependencies:
- dependency-name: com.twelvemonkeys.imageio:imageio-jpeg
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 18:24:09 +01:00
anthonyp-cns
f6a31e6ed0 Update README.md adjusting system to security as shown later in the readme for consistency (#1488)
Update README.md

Updated readme changing system to security tag to make enabling logins easy to find / implement for new users via docker environment variable
2024-06-19 06:14:52 +01:00
github-actions[bot]
7768dc9fd9 📝 Update README: Translation Progress Table (#1485)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-17 20:37:27 +01:00
Alex
b739d3847e Update messages_nl_NL.properties (#1483)
Added new translations
2024-06-17 20:36:41 +01:00
M0C
a3e5cb51b0 Polish translation (#1482)
pigers full polish translation
2024-06-17 20:36:29 +01:00
Anthony Stirling
ab7a41d155 Update README.md 2024-06-17 18:40:07 +01:00
Anthony Stirling
3576c32c52 add fat jar 2024-06-16 15:42:45 +01:00
Ludy
f43fe15193 further bug fixes when using context path (#1475)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-15 22:07:09 +01:00
arsvendg
234ae17dc8 Edit norwegian translations (#1476)
* Minor correction

* Endringer oversettelser
2024-06-15 21:40:52 +01:00
github-actions[bot]
7ee14ac794 📝 Update README: Translation Progress Table (#1473)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-15 16:08:07 +01:00
albanobattistella
ba604bda3e Update messages_it_IT.properties (#1472) 2024-06-15 15:21:08 +01:00
Ludy
036c10fc27 added: Differentiate login methods and more (#1471)
- Added Portuguese in the table (README.md)
- ApplicationProperties.class diluted, provider outsourced to its own class
- Added UnsupportedProviderException to indicate a meaningful error
- Closes #1357
- Closes #1238
2024-06-15 13:15:09 +01:00
github-actions[bot]
baa9410242 📝 Update README: Translation Progress Table (#1469)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-15 12:07:20 +01:00
Ludy
ab2fe5ef81 Add: missing string pdfOrganiser.mode.10 (#1468)
* Add: missing string pdfOrganiser.mode.10

* Update messages_it_IT.properties
2024-06-15 12:06:38 +01:00
github-actions[bot]
a926289fb0 Update 3rd Party Licenses (#1466)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-06-15 11:50:58 +01:00
Anthony Stirling
b711be3061 Update build.gradle 2024-06-15 11:50:31 +01:00
Ludy
f07ba9192b Updating build.gradle libraries (#1465) 2024-06-15 11:47:16 +01:00
github-actions[bot]
dc2f891632 Update 3rd Party Licenses (#1464)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-06-15 10:32:23 +01:00
Ludy
fe9c5a7351 Change: method write and read settings.yml #1441 (#1463)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-15 09:05:31 +01:00
github-actions[bot]
d575ba8f9a 💾 Update Version (#1461)
💾 Sync Versions
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-15 00:42:11 +01:00
Anthony Stirling
accab3b5bf Update build.gradle 2024-06-15 00:41:43 +01:00
Sebastian Espei
8cbb4367ab PDF-to-Image different page formats fix (#1460)
* Improve the PDF rendering process for pages of varying sizes

This commit includes changes to handle the rendering of PDF documents with pages of different sizes. The updated code calculates the dimensions of each page upfront and assembles a final combined image that accommodates for the differing page dimensions. This approach avoids repetitive renderings of the same page sizes.

* Refactor image preparation for Pdf to Image
2024-06-14 23:39:30 +01:00
Thomas
3ede204918 Fixed a spelling mistake in French (#1459)
"en temps que" is not correct, it should be written "en tant que"
2024-06-14 19:39:25 +01:00
imgbot[bot]
32030e8d85 [ImgBot] Optimize images (#1455)
*Total -- 1,022.17kb -> 830.16kb (18.79%)

/src/main/resources/static/images/flags/ro.svg -- 3.37kb -> 0.61kb (81.88%)
/src/main/resources/static/pdfjs/images/annotation-noicon.svg -- 0.15kb -> 0.08kb (46.84%)
/src/main/resources/static/pdfjs-legacy/images/annotation-noicon.svg -- 0.15kb -> 0.08kb (46.84%)
/src/main/resources/static/pdfjs/images/annotation-paperclip.svg -- 0.54kb -> 0.33kb (39.31%)
/src/main/resources/static/pdfjs-legacy/images/annotation-paperclip.svg -- 0.54kb -> 0.33kb (39.31%)
/images/stirling-home-dark.png -- 365.99kb -> 242.29kb (33.8%)
/docs/stirling.svg -- 3.99kb -> 2.72kb (31.87%)
/src/main/resources/static/favicon.svg -- 3.99kb -> 2.72kb (31.87%)
/images/login-light.png -- 44.09kb -> 30.17kb (31.56%)
/docs/stirling-transparent.svg -- 13.68kb -> 9.37kb (31.53%)
/images/login-dark.png -- 45.22kb -> 31.00kb (31.46%)
/src/main/resources/static/pdfjs-legacy/images/annotation-note.svg -- 1.02kb -> 0.70kb (31.12%)
/src/main/resources/static/pdfjs/images/annotation-note.svg -- 1.02kb -> 0.70kb (31.12%)
/images/settings-light.png -- 63.36kb -> 43.84kb (30.8%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-editorStamp.svg -- 0.72kb -> 0.50kb (30.52%)
/src/main/resources/static/pdfjs/images/toolbarButton-editorStamp.svg -- 0.72kb -> 0.50kb (30.52%)
/src/main/resources/static/pdfjs/images/toolBarButton-home.svg -- 1.19kb -> 0.91kb (23.4%)
/src/main/resources/static/pdfjs-legacy/images/toolBarButton-home.svg -- 1.19kb -> 0.91kb (23.4%)
/src/main/resources/static/pdfjs/images/annotation-check.svg -- 0.41kb -> 0.31kb (22.65%)
/src/main/resources/static/pdfjs-legacy/images/annotation-check.svg -- 0.41kb -> 0.31kb (22.65%)
/src/main/resources/static/pdfjs-legacy/images/annotation-newparagraph.svg -- 0.42kb -> 0.32kb (22.54%)
/src/main/resources/static/pdfjs/images/annotation-newparagraph.svg -- 0.42kb -> 0.32kb (22.54%)
/src/main/resources/static/pdfjs/images/annotation-insert.svg -- 0.40kb -> 0.31kb (22.06%)
/src/main/resources/static/pdfjs-legacy/images/annotation-insert.svg -- 0.40kb -> 0.31kb (22.06%)
/src/main/resources/static/images/flags/cz.svg -- 0.26kb -> 0.22kb (17.04%)
/src/main/resources/static/pdfjs/images/annotation-pushpin.svg -- 1.34kb -> 1.13kb (16%)
/src/main/resources/static/pdfjs-legacy/images/annotation-pushpin.svg -- 1.34kb -> 1.13kb (16%)
/src/main/resources/static/pdfjs-legacy/images/annotation-comment.svg -- 0.86kb -> 0.73kb (15.63%)
/src/main/resources/static/pdfjs/images/annotation-comment.svg -- 0.86kb -> 0.73kb (15.63%)
/src/main/resources/static/images/flags/in.svg -- 1.06kb -> 0.91kb (14.59%)
/src/main/resources/static/pdfjs-legacy/images/annotation-paragraph.svg -- 1.12kb -> 0.97kb (12.69%)
/src/main/resources/static/pdfjs/images/annotation-paragraph.svg -- 1.12kb -> 0.97kb (12.69%)
/src/main/resources/static/images/flags/kr.svg -- 1.01kb -> 0.88kb (12.61%)
/src/main/resources/static/pdfjs/images/loading-dark.svg -- 1.70kb -> 1.49kb (12.27%)
/src/main/resources/static/images/github.svg -- 2.02kb -> 1.80kb (10.69%)
/src/main/resources/static/safari-pinned-tab.svg -- 1.77kb -> 1.58kb (10.39%)
/src/main/resources/static/images/flags/jp.svg -- 0.45kb -> 0.41kb (8.82%)
/src/main/resources/static/images/flags/hu.svg -- 0.22kb -> 0.20kb (8.77%)
/src/main/resources/static/images/flags/pl.svg -- 0.21kb -> 0.20kb (8.22%)
/src/main/resources/static/images/flags/bg.svg -- 0.28kb -> 0.25kb (8.13%)
/src/main/resources/static/images/flags/ru.svg -- 0.28kb -> 0.25kb (8.13%)
/src/main/resources/static/images/flags/it.svg -- 0.28kb -> 0.26kb (7.96%)
/src/main/resources/static/images/flags/ua.svg -- 0.23kb -> 0.21kb (7.76%)
/src/main/resources/static/pdfjs-legacy/images/annotation-help.svg -- 2.12kb -> 1.96kb (7.29%)
/src/main/resources/static/pdfjs/images/annotation-help.svg -- 2.12kb -> 1.96kb (7.29%)
/src/main/resources/static/images/flags/us.svg -- 0.85kb -> 0.79kb (7.21%)
/src/main/resources/static/pdfjs/images/annotation-key.svg -- 1.42kb -> 1.33kb (6.47%)
/src/main/resources/static/pdfjs-legacy/images/annotation-key.svg -- 1.42kb -> 1.33kb (6.47%)
/src/main/resources/static/images/docker.svg -- 0.90kb -> 0.85kb (5.65%)
/src/main/resources/static/images/flags/gr.svg -- 0.85kb -> 0.80kb (5.53%)
/src/main/resources/static/images/flags/no.svg -- 0.31kb -> 0.29kb (5.35%)
/src/main/resources/static/images/flags/de.svg -- 0.21kb -> 0.19kb (5.24%)
/src/main/resources/static/images/flags/tr.svg -- 0.54kb -> 0.51kb (5.09%)
/src/main/resources/static/images/flags/pt_br.svg -- 6.34kb -> 6.03kb (4.92%)
/src/main/resources/static/images/flags/fr.svg -- 0.23kb -> 0.21kb (4.76%)
/src/main/resources/static/images/flags/nl.svg -- 0.21kb -> 0.21kb (4.55%)
/src/main/resources/static/images/flags/id.svg -- 0.17kb -> 0.17kb (4.49%)
/src/main/resources/static/pdfjs-legacy/images/loading.svg -- 1.52kb -> 1.46kb (4.04%)
/src/main/resources/static/pdfjs/images/loading.svg -- 1.52kb -> 1.46kb (4.04%)
/src/main/resources/static/images/flags/pt_pt.svg -- 8.12kb -> 7.80kb (3.91%)
/src/main/resources/static/images/flags/cn.svg -- 0.78kb -> 0.75kb (3.9%)
/src/main/resources/static/images/flags/se.svg -- 0.21kb -> 0.20kb (3.76%)
/src/main/resources/static/images/flags/gb.svg -- 0.52kb -> 0.51kb (3.18%)
/src/main/resources/static/images/flags/es-ct.svg -- 0.25kb -> 0.24kb (3.14%)
/src/main/resources/static/pdfjs/images/toolbarButton-editorHighlight.svg -- 0.89kb -> 0.86kb (2.97%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-editorHighlight.svg -- 0.89kb -> 0.86kb (2.97%)
/src/main/resources/static/pdfjs/images/editor-toolbar-delete.svg -- 0.89kb -> 0.86kb (2.64%)
/src/main/resources/static/pdfjs-legacy/images/editor-toolbar-delete.svg -- 0.89kb -> 0.86kb (2.64%)
/src/main/resources/static/images/flags/eu.svg -- 0.59kb -> 0.57kb (2.33%)
/src/main/resources/static/images/flags/sk.svg -- 1.17kb -> 1.15kb (1.92%)
/src/main/resources/static/images/flags/es.svg -- 89.66kb -> 88.07kb (1.77%)
/src/main/resources/static/pdfjs/images/toolbarButton-editorFreeText.svg -- 0.49kb -> 0.48kb (1.61%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-editorFreeText.svg -- 0.49kb -> 0.48kb (1.61%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-lastPage.svg -- 0.25kb -> 0.25kb (1.56%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-lastPage.svg -- 0.25kb -> 0.25kb (1.56%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-firstPage.svg -- 0.25kb -> 0.25kb (1.54%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-firstPage.svg -- 0.25kb -> 0.25kb (1.54%)
/src/main/resources/static/images/clipboard.svg -- 0.48kb -> 0.48kb (1.41%)
/src/main/resources/static/images/arrow-right-short.svg -- 0.31kb -> 0.30kb (1.27%)
/src/main/resources/static/pdfjs/images/toolbarButton-viewOutline.svg -- 0.32kb -> 0.32kb (1.2%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-viewOutline.svg -- 0.32kb -> 0.32kb (1.2%)
/src/main/resources/static/images/flags/rs.svg -- 179.94kb -> 177.79kb (1.19%)
/src/main/resources/static/images/flags/sa.svg -- 10.04kb -> 9.93kb (1.13%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-spreadNone.svg -- 0.39kb -> 0.38kb (1.01%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-spreadNone.svg -- 0.39kb -> 0.38kb (1.01%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-documentProperties.svg -- 0.41kb -> 0.40kb (0.96%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-documentProperties.svg -- 0.41kb -> 0.40kb (0.96%)
/src/main/resources/static/images/Files.svg -- 1.32kb -> 1.31kb (0.89%)
/src/main/resources/static/rainbow.svg -- 0.45kb -> 0.44kb (0.87%)
/src/main/resources/static/pdfjs/images/altText_add.svg -- 0.90kb -> 0.89kb (0.87%)
/src/main/resources/static/pdfjs-legacy/images/altText_add.svg -- 0.90kb -> 0.89kb (0.87%)
/src/main/resources/static/pdfjs/images/toolbarButton-zoomOut.svg -- 0.46kb -> 0.46kb (0.85%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-zoomOut.svg -- 0.46kb -> 0.46kb (0.85%)
/src/main/resources/static/pdfjs/images/toolbarButton-viewAttachments.svg -- 0.56kb -> 0.55kb (0.7%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-viewAttachments.svg -- 0.56kb -> 0.55kb (0.7%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-rotateCw.svg -- 0.56kb -> 0.56kb (0.69%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-rotateCw.svg -- 0.56kb -> 0.56kb (0.69%)
/src/main/resources/static/pdfjs/images/findbarButton-next.svg -- 0.56kb -> 0.56kb (0.69%)
/src/main/resources/static/pdfjs-legacy/images/findbarButton-next.svg -- 0.56kb -> 0.56kb (0.69%)
/src/main/resources/static/pdfjs-legacy/images/findbarButton-previous.svg -- 0.56kb -> 0.56kb (0.69%)
/src/main/resources/static/pdfjs/images/findbarButton-previous.svg -- 0.56kb -> 0.56kb (0.69%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-rotateCcw.svg -- 0.58kb -> 0.58kb (0.67%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-rotateCcw.svg -- 0.58kb -> 0.58kb (0.67%)
/src/main/resources/static/moon.svg -- 0.58kb -> 0.58kb (0.67%)
/src/main/resources/static/pdfjs/images/toolbarButton-currentOutlineItem.svg -- 0.59kb -> 0.59kb (0.66%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-currentOutlineItem.svg -- 0.59kb -> 0.59kb (0.66%)
/src/main/resources/static/images/flags/hr.svg -- 40.21kb -> 39.97kb (0.6%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-viewLayers.svg -- 0.66kb -> 0.65kb (0.6%)
/src/main/resources/static/pdfjs/images/toolbarButton-viewLayers.svg -- 0.66kb -> 0.65kb (0.6%)
/src/main/resources/static/pdfjs/images/toolbarButton-presentationMode.svg -- 0.67kb -> 0.66kb (0.59%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-menuArrow.svg -- 0.67kb -> 0.66kb (0.59%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-presentationMode.svg -- 0.67kb -> 0.66kb (0.59%)
/src/main/resources/static/pdfjs/images/toolbarButton-menuArrow.svg -- 0.67kb -> 0.66kb (0.59%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-pageUp.svg -- 0.67kb -> 0.66kb (0.59%)
/src/main/resources/static/pdfjs/images/toolbarButton-pageUp.svg -- 0.67kb -> 0.66kb (0.59%)
/src/main/resources/static/pdfjs/images/toolbarButton-download.svg -- 1.01kb -> 1.01kb (0.58%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-download.svg -- 1.01kb -> 1.01kb (0.58%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-pageDown.svg -- 0.68kb -> 0.68kb (0.57%)
/src/main/resources/static/pdfjs/images/toolbarButton-pageDown.svg -- 0.68kb -> 0.68kb (0.57%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-spreadOdd.svg -- 0.69kb -> 0.69kb (0.56%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-spreadOdd.svg -- 0.69kb -> 0.69kb (0.56%)
/src/main/resources/static/pdfjs-legacy/images/altText_done.svg -- 1.06kb -> 1.06kb (0.55%)
/src/main/resources/static/pdfjs/images/altText_done.svg -- 1.06kb -> 1.06kb (0.55%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-scrollPage.svg -- 0.71kb -> 0.71kb (0.55%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-scrollPage.svg -- 0.71kb -> 0.71kb (0.55%)
/src/main/resources/static/images/book.svg -- 0.75kb -> 0.75kb (0.52%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-spreadEven.svg -- 0.76kb -> 0.75kb (0.52%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-spreadEven.svg -- 0.76kb -> 0.75kb (0.52%)
/src/main/resources/static/pdfjs-legacy/images/gv-toolbarButton-download.svg -- 0.76kb -> 0.76kb (0.51%)
/src/main/resources/static/pdfjs/images/gv-toolbarButton-download.svg -- 0.76kb -> 0.76kb (0.51%)
/src/main/resources/static/pdfjs/images/toolbarButton-editorInk.svg -- 1.16kb -> 1.16kb (0.5%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-editorInk.svg -- 1.16kb -> 1.16kb (0.5%)
/src/main/resources/static/sun.svg -- 0.81kb -> 0.80kb (0.48%)
/src/main/resources/static/pdfjs/images/toolbarButton-bookmark.svg -- 0.84kb -> 0.84kb (0.46%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-bookmark.svg -- 0.84kb -> 0.84kb (0.46%)
/src/main/resources/static/images/file-earmark-pdf.svg -- 1.50kb -> 1.49kb (0.46%)
/src/main/resources/static/pdfjs/images/cursor-editorInk.svg -- 1.29kb -> 1.29kb (0.45%)
/src/main/resources/static/pdfjs-legacy/images/cursor-editorInk.svg -- 1.29kb -> 1.29kb (0.45%)
/src/main/resources/static/pdfjs/images/toolbarButton-print.svg -- 0.91kb -> 0.90kb (0.43%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-print.svg -- 0.91kb -> 0.90kb (0.43%)
/src/main/resources/static/pdfjs/images/toolbarButton-zoomIn.svg -- 0.94kb -> 0.93kb (0.42%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-zoomIn.svg -- 0.94kb -> 0.93kb (0.42%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-scrollVertical.svg -- 0.95kb -> 0.94kb (0.41%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-scrollVertical.svg -- 0.95kb -> 0.94kb (0.41%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-scrollHorizontal.svg -- 0.95kb -> 0.94kb (0.41%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-scrollHorizontal.svg -- 0.95kb -> 0.94kb (0.41%)
/src/main/resources/static/pdfjs/images/toolbarButton-secondaryToolbarToggle.svg -- 1.05kb -> 1.05kb (0.37%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-secondaryToolbarToggle.svg -- 1.05kb -> 1.05kb (0.37%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-selectTool.svg -- 1.06kb -> 1.06kb (0.37%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-selectTool.svg -- 1.06kb -> 1.06kb (0.37%)
/src/main/resources/static/pdfjs/images/loading-icon.gif -- 2.49kb -> 2.48kb (0.35%)
/src/main/resources/static/pdfjs-legacy/images/loading-icon.gif -- 2.49kb -> 2.48kb (0.35%)
/src/main/resources/static/pdfjs/images/cursor-editorFreeText.svg -- 1.42kb -> 1.41kb (0.34%)
/src/main/resources/static/pdfjs-legacy/images/cursor-editorFreeText.svg -- 1.42kb -> 1.41kb (0.34%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-scrollWrapped.svg -- 1.20kb -> 1.20kb (0.33%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-scrollWrapped.svg -- 1.20kb -> 1.20kb (0.33%)
/src/main/resources/static/pdfjs/images/toolbarButton-search.svg -- 1.21kb -> 1.20kb (0.32%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-search.svg -- 1.21kb -> 1.20kb (0.32%)
/src/main/resources/static/images/discord.svg -- 1.24kb -> 1.24kb (0.31%)
/src/main/resources/static/pdfjs/images/secondaryToolbarButton-handTool.svg -- 1.31kb -> 1.31kb (0.3%)
/src/main/resources/static/pdfjs-legacy/images/secondaryToolbarButton-handTool.svg -- 1.31kb -> 1.31kb (0.3%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-viewThumbnail.svg -- 1.36kb -> 1.36kb (0.29%)
/src/main/resources/static/pdfjs/images/toolbarButton-viewThumbnail.svg -- 1.36kb -> 1.36kb (0.29%)
/src/main/resources/static/pdfjs/images/toolbarButton-openFile.svg -- 1.37kb -> 1.36kb (0.29%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-openFile.svg -- 1.37kb -> 1.36kb (0.29%)
/src/main/resources/static/pdfjs-legacy/images/toolbarButton-sidebarToggle.svg -- 1.52kb -> 1.52kb (0.26%)
/src/main/resources/static/pdfjs/images/toolbarButton-sidebarToggle.svg -- 1.52kb -> 1.52kb (0.26%)
/src/main/resources/static/images/update.svg -- 0.40kb -> 0.40kb (0.24%)
/src/main/resources/static/pdfjs/images/cursor-editorFreeHighlight.svg -- 2.87kb -> 2.86kb (0.2%)
/src/main/resources/static/pdfjs-legacy/images/cursor-editorFreeHighlight.svg -- 2.87kb -> 2.86kb (0.2%)
/src/main/resources/static/pdfjs-legacy/images/cursor-editorTextHighlight.svg -- 5.28kb -> 5.27kb (0.19%)
/src/main/resources/static/pdfjs/images/cursor-editorTextHighlight.svg -- 5.28kb -> 5.27kb (0.19%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2024-06-14 19:38:54 +01:00
tkymmm
b7d55a3f78 Update messages_ja_JP.properties (#1457)
Updated Japanese translation
2024-06-14 19:32:39 +01:00
albanobattistella
699545ddbe Update messages_it_IT.properties (#1454) 2024-06-13 21:51:39 +01:00
Pavlo K
54b3f17bf9 Add missing of Ukrainian translation to the resource file (#1448) 2024-06-13 18:14:09 +01:00
HHHHHMMMM
f2015cecbd When converting PDF to word, add parameters to speed up soffice startup (#1450)
When converting PDF to word, add parameters to speed up soffice startup
2024-06-13 18:13:38 +01:00
Sebastian Espei
f60a8d87d2 Add Odd-Even Merge operation mode (#1445)
* Add ODD_EVEN_MERGE sort type

* Add process method to merge odd and even PDF pages

* Add test cases for Odd-Even merge method

* Add Odd-Even Merge mode in PDF Organizer webpage

This also add a new translatable text message variable pdfOrganiser.mode.10 with translation for english and german

* Add ODD_EVEN_MERGE documentation to RearrangePagesRequest

* Add english translation for pdfOrganiser.mode.10

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-12 22:21:02 +01:00
github-actions[bot]
eccebd265f 📝 Update README: Translation Progress Table (#1447)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-12 22:15:32 +01:00
Anthony Stirling
889c9a114b survey (#1446)
* survey

* LANGS
2024-06-12 22:12:42 +01:00
github-actions[bot]
9fd561ecf6 📝 Update README: Translation Progress Table (#1431)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-12 20:36:35 +01:00
Ludy
1e72960c5f Bugfix: missing contextPath (#1434) 2024-06-12 20:36:18 +01:00
小麥
5a50c54f29 Update messages_zh_TW.properties: Translate English sentence to Chinese (#1438)
Update messages_zh_TW.properties

Translate more sentence to zh_TW.
Fix sentence to fit the "Chinese copywriting guidelines".
2024-06-12 20:34:56 +01:00
Ludy
446bc68768 change to Pdf.js-Legacy Version 4.3.136 (#1444)
* add: PDF.js-Legacy

* change path
2024-06-12 20:33:25 +01:00
Abdulwahhab A Alzahrani
76660eb791 Update messages_ar_AR.properties (#1430)
translate to Arabic
2024-06-09 21:20:35 +01:00
678 changed files with 159201 additions and 4601 deletions

2
.gitattributes vendored
View File

@@ -3,6 +3,8 @@
# Ignore all JavaScript files in a directory
src/main/resources/static/pdfjs/* linguist-vendored
src/main/resources/static/pdfjs/** linguist-vendored
src/main/resources/static/pdfjs-legacy/* linguist-vendored
src/main/resources/static/pdfjs-legacy/** linguist-vendored
src/main/resources/static/css/bootstrap-icons.css linguist-vendored
src/main/resources/static/css/bootstrap.min.css linguist-vendored
src/main/resources/static/css/fonts/* linguist-vendored

49
.github/labeler-config.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
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/static/**/*'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/**'
Java:
- changed-files:
- any-glob-to-any-file: 'src/main/java/**/*.java'
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:
- changed-files:
- 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

18
.github/workflows/auto-labeler.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: "Pull Request Labeler"
on:
pull_request_target:
types: [opened, synchronize]
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler-config.yml
sync-labels: true

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

32
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Close stale issues
on:
schedule:
- cron: "30 0 * * *"
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: 30 days stale issues
uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30
days-before-close: 7
stale-issue-message: >
This issue has been automatically marked as stale because it has had no recent activity.
It will be closed if no further activity occurs. Thank you for your contributions.
close-issue-message: >
This issue has been automatically closed because it has had no recent activity after being marked as stale.
Please reopen if you need further assistance.
stale-issue-label: "Stale"
remove-stale-when-updated: true
only-issue-labels: "more-info-needed"
days-before-pr-stale: -1 # Prevents PRs from being marked as stale
days-before-pr-close: -1 # Prevents PRs from being closed
start-date: '2024-07-06T00:00:00Z' # ISO 8601 Format

View File

@@ -7,7 +7,7 @@ on:
paths:
- "build.gradle"
- "src/main/resources/messages_*.properties"
- "scripts/translation_status.toml"
- "scripts/ignore_translation.toml"
permissions:
contents: write
@@ -17,9 +17,9 @@ jobs:
sync-versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install dependencies
@@ -36,7 +36,7 @@ jobs:
git diff --staged --quiet || git commit -m ":floppy_disk: Sync Versions
> Made via sync_files.yml" || echo "no changes"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6.0.1
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update files
@@ -51,12 +51,13 @@ 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:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install dependencies
@@ -73,7 +74,7 @@ jobs:
git diff --staged --quiet || git commit -m ":memo: Sync README
> Made via sync_files.yml" || echo "no changes"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6.0.1
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update files
@@ -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

View File

@@ -6,9 +6,11 @@ repos:
args:
- --fix
- --line-length=127
files: ^((.github/scripts)/.+)?[^/]+\.py$
files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
exclude: (split_photos.py)
- id: ruff-format
files: ^((.github/scripts)/.+)?[^/]+\.py$
files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
exclude: (split_photos.py)
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
hooks:
@@ -33,5 +35,5 @@ repos:
# args: ["--replace_with= "]
entry: python .github/scripts/check_tabulator.py
language: python
exclude: ^src/main/resources/static/pdfjs/
exclude: ^(src/main/resources/static/pdfjs|src/main/resources/static/pdfjs-legacy)
files: ^.*(\.html|\.css|\.js)$

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
}

40
DATABASE.md Normal file
View File

@@ -0,0 +1,40 @@
# New Database Backup and Import Functionality
**Full activation will take place on approximately January 5th, 2025!**
Why is the waiting time six months?
There are users who only install updates sporadically; if they skip the preparation, it can/will lead to data loss in the database.
## Functionality Overview
The newly introduced feature enhances the application with robust database backup and import capabilities. This feature is designed to ensure data integrity and provide a straightforward way to manage database backups. Here's how it works:
1. Automatic Backup Creation
- The system automatically creates a database backup every day at midnight. This ensures that there is always a recent backup available, minimizing the risk of data loss.
2. Manual Backup Export
- Admin actions that modify the user database trigger a manual export of the database. This keeps the backup up-to-date with the latest changes and provides an extra layer of data security.
3. Importing Database Backups
- Admin users can import a database backup either via the web interface or API endpoints. This allows for easy restoration of the database to a previous state in case of data corruption or other issues.
- The import process ensures that the database structure and data are correctly restored, maintaining the integrity of the application.
4. Managing Backup Files
- Admins can view a list of all existing backup files, along with their creation dates and sizes. This helps in managing storage and identifying the most recent or relevant backups.
- Backup files can be downloaded for offline storage or transferred to other environments, providing flexibility in database management.
- Unnecessary backup files can be deleted through the interface to free up storage space and maintain an organized backup directory.
## User Interface
### Web Interface
1. Upload SQL files to import database backups.
2. View details of existing backups, such as file names, creation dates, and sizes.
3. Download backup files for offline storage.
4. Delete outdated or unnecessary backup files.
### API Endpoints
1. Import database backups by uploading SQL files.
2. Download backup files.
3. Delete backup files.
This new functionality streamlines database management, ensuring that backups are always available and easy to manage, thus improving the reliability and resilience of the application.

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 \

164
README.md
View File

@@ -9,6 +9,7 @@
[![Github Sponsor](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle)
[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
[<img src="https://www.ssdnodes.com/wp-content/uploads/2023/11/footer-logo.svg" alt="Name" height="40">](https://www.ssdnodes.com/manage/aff.php?aff=2216&register=true)
This is a robust, locally hosted web-based PDF manipulation tool using Docker. It enables you to carry out various operations on PDF files, including splitting, merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application has evolved to encompass a comprehensive set of features, addressing all your PDF requirements.
@@ -21,10 +22,11 @@ All files and PDFs exist either exclusively on the client side, reside in server
## Features
- Dark mode support.
- Custom download options (see [here](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/images/settings.png) for example)
- Custom download options
- Parallel file processing and downloads
- API for integration with external scripts
- Optional Login and Authentication support (see [here](https://github.com/Stirling-Tools/Stirling-PDF/tree/main#login-authentication) for documentation)
- Database Backup and Import (see [here](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DATABASE.md) for documentation)
## **PDF Features**
@@ -82,7 +84,8 @@ All files and PDFs exist either exclusively on the client side, reside in server
- Get all information on a PDF to view or export as JSON.
For a overview of the tasks and the technology each uses please view [Endpoint-groups.md](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Endpoint-groups.md)
Demo of the app is available [here](https://stirlingpdf.io). username: demo, password: demo
Demo of the app is available [here](https://stirlingpdf.io).
## Technologies used
@@ -105,33 +108,36 @@ Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/LocalRunGui
https://hub.docker.com/r/frooodle/s-pdf
Stirling PDF has 2 different versions, a Full version and ultra-Lite version. Depending on the types of features you use you may want a smaller image to save on space.
Stirling PDF has 3 different versions, a Full version and ultra-Lite version as well as a 'Fat' version. Depending on the types of features you use you may want a smaller image to save on space.
To see what the different versions offer please look at our [version mapping](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Version-groups.md)
For people that don't mind about space optimization just use the latest tag.
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/frooodle/s-pdf/latest?label=Stirling-PDF%20Full)
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/frooodle/s-pdf/latest-ultra-lite?label=Stirling-PDF%20Ultra-Lite)
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/frooodle/s-pdf/latest-fat?label=Stirling-PDF%20Fat)
Docker Run
Please note in below examples you may need to change the volume paths as needed, current examples install them to the current working directory
eg ``./extraConfigs:/configs`` to ``/opt/stirlingpdf/extraConfigs:/configs``
### Docker Run
```bash
docker run -d \
-p 8080:8080 \
-v /location/of/trainingData:/usr/share/tessdata \
-v /location/of/extraConfigs:/configs \
-v /location/of/logs:/logs \
-v ./trainingData:/usr/share/tessdata \
-v ./extraConfigs:/configs \
-v ./logs:/logs \
-e DOCKER_ENABLE_SECURITY=false \
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
-e LANGS=en_GB \
--name stirling-pdf \
frooodle/s-pdf:latest
Can also add these for customisation but are not required
-v /location/of/customFiles:/customFiles \
```
Docker Compose
### Docker Compose
```yaml
version: '3.3'
@@ -141,10 +147,10 @@ services:
ports:
- '8080:8080'
volumes:
- /location/of/trainingData:/usr/share/tessdata #Required for extra OCR languages
- /location/of/extraConfigs:/configs
# - /location/of/customFiles:/customFiles/
# - /location/of/logs:/logs/
- ./trainingData:/usr/share/tessdata #Required for extra OCR languages
- ./extraConfigs:/configs
# - ./customFiles:/customFiles/
# - ./logs:/logs/
environment:
- DOCKER_ENABLE_SECURITY=false
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
@@ -159,41 +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) | ![40%](https://geps.dev/progress/40) |
| German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) |
| Spanish (Español) (es_ES) | ![94%](https://geps.dev/progress/94) |
| Simplified Chinese (简体中文) (zh_CN) | ![95%](https://geps.dev/progress/95) |
| Traditional Chinese (繁體中文) (zh_TW) | ![94%](https://geps.dev/progress/94) |
| Catalan (Català) (ca_CA) | ![49%](https://geps.dev/progress/49) |
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) |
| Greek (Ελληνικά) (el_GR) | ![82%](https://geps.dev/progress/82) |
| Hindi (हिंदी) (hi_IN) | ![77%](https://geps.dev/progress/77) |
| Hungarian (Magyar) (hu_HU) | ![76%](https://geps.dev/progress/76) |
| 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) |
| Swedish (Svenska) (sv_SE) | ![40%](https://geps.dev/progress/40) |
| Polish (Polski) (pl_PL) | ![42%](https://geps.dev/progress/42) |
| 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) |
| Korean (한국어) (ko_KR) | ![87%](https://geps.dev/progress/87) |
| Portuguese Brazilian (Português) (pt_BR) | ![61%](https://geps.dev/progress/61) |
| Russian (Русский) (ru_RU) | ![86%](https://geps.dev/progress/86) |
| Basque (Euskara) (eu_ES) | ![63%](https://geps.dev/progress/63) |
| Japanese (日本語) (ja_JP) | ![87%](https://geps.dev/progress/87) |
| Dutch (Nederlands) (nl_NL) | ![84%](https://geps.dev/progress/84) |
| Greek (Ελληνικά) (el_GR) | ![85%](https://geps.dev/progress/85) |
| Turkish (Türkçe) (tr_TR) | ![97%](https://geps.dev/progress/97) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![78%](https://geps.dev/progress/78) |
| Hindi (हिंदी) (hi_IN) | ![79%](https://geps.dev/progress/79) |
| Hungarian (Magyar) (hu_HU) | ![77%](https://geps.dev/progress/77) |
| Bulgarian (Български) (bg_BG) | ![97%](https://geps.dev/progress/97) |
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![80%](https://geps.dev/progress/80) |
| Ukrainian (Українська) (uk_UA) | ![86%](https://geps.dev/progress/86) |
| Slovakian (Slovensky) (sk_SK) | ![94%](https://geps.dev/progress/94) |
| Czech (Česky) (cs_CZ) | ![93%](https://geps.dev/progress/93) |
| Croatian (Hrvatski) (hr_HR) | ![98%](https://geps.dev/progress/98) |
| Norwegian (Norsk) (no_NB) | ![98%](https://geps.dev/progress/98) |
| 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.)
@@ -205,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
@@ -214,11 +225,11 @@ Environment variables are also supported and would override the settings file
For example in the settings.yml you have
```yaml
system:
security:
enableLogin: 'true'
```
To have this via an environment variable you would have ``SYSTEM_ENABLELOGIN``
To have this via an environment variable you would have ``SECURITY_ENABLELOGIN``
The Current list of settings is
@@ -228,35 +239,36 @@ security:
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
loginAttemptCount: 5 # lock user account after 5 tries
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
# initialLogin:
# username: "admin" # Initial username for the first login
# password: "stirling" # Initial password for the first login
# oauth2:
# enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
# issuer: "" # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
# clientId: "" # Client ID from your provider
# clientSecret: "" # Client Secret from your provider
# autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
# useAsUsername: "email" # Default is 'email'; custom fields can be used as the username
# scopes: "openid, profile, email" # Specify the scopes for which the application will request permissions
# provider: "google" # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
# client:
# google:
# clientId: "" # Client ID for Google OAuth2
# clientSecret: "" # Client Secret for Google OAuth2
# scopes: "https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile" # Scopes for Google OAuth2
# useAsUsername: "email" # Field to use as the username for Google OAuth2
# github:
# clientId: "" # Client ID for GitHub OAuth2
# clientSecret: "" # Client Secret for GitHub OAuth2
# scopes: "read:user" # Scope for GitHub OAuth2
# useAsUsername: "login" # Field to use as the username for GitHub OAuth2
# keycloak:
# issuer: "http://192.168.0.123:8888/realms/stirling-pdf" # URL of the Keycloak realm's OpenID Connect Discovery endpoint
# clientId: "stirling-pdf" # Client ID for Keycloak OAuth2
# clientSecret: "" # Client Secret for Keycloak OAuth2
# scopes: "openid, profile, email" # Scopes for Keycloak OAuth2
# useAsUsername: "email" # Field to use as the username for Keycloak OAuth2
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
initialLogin:
username: '' # Initial username for the first login
password: '' # Initial password for the first login
oauth2:
enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
client:
keycloak:
issuer: '' # URL of the Keycloak realm's OpenID Connect Discovery endpoint
clientId: '' # Client ID for Keycloak OAuth2
clientSecret: '' # Client Secret for Keycloak OAuth2
scopes: openid, profile, email # Scopes for Keycloak OAuth2
useAsUsername: preferred_username # Field to use as the username for Keycloak OAuth2
google:
clientId: '' # Client ID for Google OAuth2
clientSecret: '' # Client Secret for Google OAuth2
scopes: https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile # Scopes for Google OAuth2
useAsUsername: email # Field to use as the username for Google OAuth2
github:
clientId: '' # Client ID for GitHub OAuth2
clientSecret: '' # Client Secret for GitHub OAuth2
scopes: read:user # Scope for GitHub OAuth2
useAsUsername: login # Field to use as the username for GitHub OAuth2
issuer: '' # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
clientId: '' # Client ID from your provider
clientSecret: '' # Client Secret from your provider
autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
useAsUsername: email # Default is 'email'; custom fields can be used as the username
scopes: openid, profile, email # Specify the scopes for which the application will request permissions
provider: google # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
system:
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
@@ -267,9 +279,9 @@ system:
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template html files
ui:
appName: null # Application's visible name
homeDescription: null # Short description or tagline shown on homepage.
appNameNavbar: null # Name displayed on the navigation bar
appName: '' # Application's visible name
homeDescription: '' # Short description or tagline shown on homepage.
appNameNavbar: '' # Name displayed on the navigation bar
endpoints:
toRemove: [] # List endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
@@ -303,7 +315,7 @@ For those wanting to use Stirling-PDFs backend API to link with their own custom
![stirling-login](images/login-light.png)
### Prerequisites:
### Prerequisites
- User must have the folder ./configs volumed within docker so that it is retained during updates.
- Docker users must download the security jar version by setting ``DOCKER_ENABLE_SECURITY`` to ``true`` in environment variables.

View File

@@ -1,4 +1,7 @@
| Technology | Ultra-Lite | Full |
|All versions in a Docker environment can download Calibre as a optional extra at runtime to support `book-to-pdf` and `pdf-to-book` using parameter ``INSTALL_BOOK_AND_ADVANCED_HTML_OPS``.
The 'Fat' container contains all those found in 'Full' with security jar along with this Calibre install.
Technology | Ultra-Lite | Full |
| ---------- | :--------: | :---: |
| Java | ✔️ | ✔️ |
| JavaScript | ✔️ | ✔️ |

View File

@@ -1,24 +1,29 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.4'
id 'io.spring.dependency-management' version '1.1.3'
id 'org.springdoc.openapi-gradle-plugin' version '1.8.0'
id "java"
id "org.springframework.boot" version "3.3.0"
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'
id 'com.diffplug.spotless' version '6.25.0'
id 'com.github.jk1.dependency-license-report' version '2.6'
id "edu.sc.seis.launch4j" version "3.0.5"
id "com.diffplug.spotless" version "6.25.0"
id "com.github.jk1.dependency-license-report" version "2.8"
}
import com.github.jk1.license.render.*
group = 'stirling.software'
version = '0.26.0'
ext {
springBootVersion = "3.3.2"
}
//17 is lowest but we support and recommend 21
sourceCompatibility = '17'
group = "stirling.software"
version = "0.26.2"
// 17 is lowest but we support and recommend 21
sourceCompatibility = "17"
repositories {
mavenCentral()
maven { url "https://jitpack.io" }
}
licenseReport {
@@ -28,15 +33,18 @@ licenseReport {
sourceSets {
main {
java {
if (System.getenv('DOCKER_ENABLE_SECURITY') == 'false') {
exclude 'stirling/software/SPDF/config/security/**'
exclude 'stirling/software/SPDF/controller/api/UserController.java'
exclude 'stirling/software/SPDF/controller/web/AccountWebController.java'
exclude 'stirling/software/SPDF/model/ApiKeyAuthenticationToken.java'
exclude 'stirling/software/SPDF/model/Authority.java'
exclude 'stirling/software/SPDF/model/PersistentLogin.java'
exclude 'stirling/software/SPDF/model/User.java'
exclude 'stirling/software/SPDF/repository/**'
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
exclude "stirling/software/SPDF/config/security/**"
exclude "stirling/software/SPDF/controller/api/UserController.java"
exclude "stirling/software/SPDF/controller/api/DatabaseController.java"
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"
exclude "stirling/software/SPDF/repository/**"
}
}
}
@@ -49,34 +57,34 @@ openApi {
}
launch4j {
icon = "${projectDir}/src/main/resources/static/favicon.ico"
icon = "${projectDir}/src/main/resources/static/favicon.ico"
outfile="Stirling-PDF.exe"
headerType="console"
jarTask = tasks.bootJar
outfile="Stirling-PDF.exe"
headerType="console"
jarTask = tasks.bootJar
errTitle="Encountered error, Do you have Java 21?"
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
variables=["BROWSER_OPEN=true", "ENDPOINTS_GROUPS_TO_REMOVE=CLI"]
jreMinVersion="17"
errTitle="Encountered error, Do you have Java 21?"
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
variables=["BROWSER_OPEN=true", "ENDPOINTS_GROUPS_TO_REMOVE=CLI"]
jreMinVersion="17"
mutexName="Stirling-PDF"
windowTitle="Stirling-PDF"
mutexName="Stirling-PDF"
windowTitle="Stirling-PDF"
messagesStartupError="An error occurred while starting Stirling-PDF"
//messagesJreNotFoundError="This application requires a Java Runtime Environment, Please download Java 17."
messagesJreVersionError="You are running the wrong version of Java, Please download Java 21."
messagesLauncherError="Java is corrupted. Please uninstall and then install Java 21."
messagesInstanceAlreadyExists="Stirling-PDF is already running."
messagesStartupError="An error occurred while starting Stirling-PDF"
// messagesJreNotFoundError="This application requires a Java Runtime Environment, Please download Java 17."
messagesJreVersionError="You are running the wrong version of Java, Please download Java 21."
messagesLauncherError="Java is corrupted. Please uninstall and then install Java 21."
messagesInstanceAlreadyExists="Stirling-PDF is already running."
}
spotless {
java {
target project.fileTree('src/main/java')
googleJavaFormat('1.19.1').aosp().reorderImports(false)
googleJavaFormat("1.22.0").aosp().reorderImports(false)
importOrder('java', 'javax', 'org', 'com', 'net', 'io')
importOrder("java", "javax", "org", "com", "net", "io")
toggleOffOn()
trimTrailingWhitespace()
indentWithSpaces()
@@ -84,127 +92,137 @@ spotless {
}
}
tasks.wrapper {
gradleVersion = "8.7"
}
dependencies {
//security updates
implementation 'ch.qos.logback:logback-classic:1.5.3'
implementation 'ch.qos.logback:logback-core:1.5.3'
implementation 'org.springframework:spring-webmvc:6.1.5'
implementation "ch.qos.logback:logback-classic:1.5.6"
implementation "ch.qos.logback:logback-core:1.5.6"
implementation "org.springframework:spring-webmvc:6.1.9"
implementation("io.github.pixee:java-security-toolkit:1.1.3")
implementation 'org.yaml:snakeyaml:2.2'
// implementation "org.yaml:snakeyaml:2.2"
implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4'
// Exclude Tomcat and include Jetty
implementation('org.springframework.boot:spring-boot-starter-web:3.2.4') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion") {
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
implementation 'org.springframework.boot:spring-boot-starter-jetty:3.2.4'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.4'
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.4'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.4"
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.2.4'
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
//2.2.x requires rebuild of DB file.. need migration path
implementation "com.h2database:h2:2.1.214"
// implementation "com.h2database:h2:2.2.224"
}
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.4'
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
// Batik
implementation 'org.apache.xmlgraphics:batik-all:1.17'
implementation "org.apache.xmlgraphics:batik-all:1.17"
// TwelveMonkeys
implementation 'com.twelvemonkeys.imageio:imageio-batik:3.10.1'
implementation 'com.twelvemonkeys.imageio:imageio-bmp:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-hdr:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-icns:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-iff:3.10.1'
implementation 'com.twelvemonkeys.imageio:imageio-jpeg:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-pcx:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-pict:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-pnm:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-psd:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-sgi:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-tga:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-thumbsdb:3.10.1'
implementation 'com.twelvemonkeys.imageio:imageio-tiff:3.10.1'
implementation 'com.twelvemonkeys.imageio:imageio-webp:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-xwd:3.10.1'
implementation "com.twelvemonkeys.imageio:imageio-batik:3.10.1"
implementation "com.twelvemonkeys.imageio:imageio-bmp:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-hdr:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-icns:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-iff:3.10.1"
implementation "com.twelvemonkeys.imageio:imageio-jpeg:3.11.0"
// implementation "com.twelvemonkeys.imageio:imageio-pcx:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-pict:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-pnm:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-psd:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-sgi:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-tga:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-thumbsdb:3.10.1"
implementation "com.twelvemonkeys.imageio:imageio-tiff:3.10.1"
implementation "com.twelvemonkeys.imageio:imageio-webp:3.10.1"
// implementation "com.twelvemonkeys.imageio:imageio-xwd:3.10.1"
implementation 'commons-io:commons-io:2.16.1'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
implementation "commons-io:commons-io:2.16.1"
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
//general PDF
// https://mvnrepository.com/artifact/com.opencsv/opencsv
implementation ('com.opencsv:opencsv:5.9') {
exclude group: 'commons-logging', module: 'commons-logging'
implementation ("com.opencsv:opencsv:5.9") {
exclude group: "commons-logging", module: "commons-logging"
}
implementation ('org.apache.pdfbox:pdfbox:3.0.2'){
exclude group: 'commons-logging', module: 'commons-logging'
implementation ("org.apache.pdfbox:pdfbox:3.0.2") {
exclude group: "commons-logging", module: "commons-logging"
}
implementation ('org.apache.pdfbox:xmpbox:3.0.2'){
exclude group: 'commons-logging', module: 'commons-logging'
implementation ("org.apache.pdfbox:xmpbox:3.0.2") {
exclude group: "commons-logging", module: "commons-logging"
}
implementation "com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4"
implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.4'
implementation 'io.micrometer:micrometer-core:1.12.4'
implementation group: 'com.google.zxing', name: 'core', version: '3.5.3'
implementation "org.bouncycastle:bcprov-jdk18on:1.78.1"
implementation "org.bouncycastle:bcpkix-jdk18on:1.78.1"
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
implementation "io.micrometer:micrometer-core:1.13.0"
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
// https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation 'org.commonmark:commonmark:0.22.0'
implementation 'org.commonmark:commonmark-ext-gfm-tables:0.22.0'
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'
implementation "org.commonmark:commonmark:0.22.0"
implementation "org.commonmark:commonmark-ext-gfm-tables:0.22.0"
// https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17
implementation "com.bucket4j:bucket4j_jdk17-core:8.12.1"
implementation 'com.fathzer:javaluator:3.0.3'
implementation "com.fathzer:javaluator:3.0.4"
developmentOnly("org.springframework.boot:spring-boot-devtools:3.2.4")
compileOnly 'org.projectlombok:lombok:1.18.32'
annotationProcessor 'org.projectlombok:lombok:1.18.32'
developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion")
compileOnly "org.projectlombok:lombok:1.18.32"
annotationProcessor "org.projectlombok:lombok:1.18.32"
testImplementation 'org.mockito:mockito-inline:3.12.4'
}
tasks.withType(JavaCompile).configureEach {
dependsOn 'spotlessApply'
options.encoding = "UTF-8"
dependsOn "spotlessApply"
}
compileJava {
options.compilerArgs << '-parameters'
options.compilerArgs << "-parameters"
}
task writeVersion {
def propsFile = file('src/main/resources/version.properties')
def propsFile = file("src/main/resources/version.properties")
def props = new Properties()
props.setProperty('version', version)
props.setProperty("version", version)
props.store(propsFile.newWriter(), null)
}
swaggerhubUpload {
//dependsOn generateOpenApiDocs // Depends on your task generating Swagger docs
api 'Stirling-PDF' // The name of your API on SwaggerHub
owner 'Frooodle' // Your SwaggerHub username (or organization name)
api "Stirling-PDF" // The name of your API on SwaggerHub
owner "Frooodle" // Your SwaggerHub username (or organization name)
version project.version // The version of your API
inputFile './SwaggerDoc.json' // The path to your Swagger docs
token "${System.getenv('SWAGGERHUB_API_KEY')}" // Your SwaggerHub API key, passed as an environment variable
oas '3.0.0' // The version of the OpenAPI Specification you're using
inputFile "./SwaggerDoc.json" // The path to your Swagger docs
token "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
oas "3.0.0" // The version of the OpenAPI Specification you"re using
}
jar {
enabled = false
manifest {
attributes 'Implementation-Title': 'Stirling-PDF',
'Implementation-Version': project.version
attributes "Implementation-Title": "Stirling-PDF",
"Implementation-Version": project.version
}
}
tasks.named('test') {
tasks.named("test") {
useJUnitPlatform()
}

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 0.26.0
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}'"

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -1,110 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 512 512"
style="enable-background:new 0 0 512 512;"
xml:space="preserve"
sodipodi:docname="favicon.svg"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
inkscape:export-filename="favicon.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs173">
<linearGradient
id="XMLID_5_"
gradientUnits="userSpaceOnUse"
x1="304.496"
y1="422.9102"
x2="316.036"
y2="326.2626">
<stop
offset="0"
style="stop-color:#DCF1F3"
id="stop156" />
<stop
offset="1"
style="stop-color:#C2C2C9"
id="stop158" />
</linearGradient>
</defs><sodipodi:namedview
id="namedview171"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.4142136"
inkscape:cx="219.91021"
inkscape:cy="232.63813"
inkscape:window-width="3840"
inkscape:window-height="2054"
inkscape:window-x="2869"
inkscape:window-y="-11"
inkscape:window-maximized="1"
inkscape:current-layer="XMLID_4_" />
<style
type="text/css"
id="style150">
.st0{fill:#FFFFFF;}
.st1{fill:#C02223;}
.st2{fill:#882425;}
.st3{fill:url(#XMLID_5_);}
.st4{fill:url(#XMLID_7_);}
</style>
<g
id="XMLID_4_">
<path
id="XMLID_131_"
class="st1"
d="M 347.01402,14.355825 98.978019,69.02261 C 73.825483,74.547445 55.942464,96.792175 55.942464,122.52628 v 315.06096 c 0,22.39012 16.719895,41.14548 38.819234,43.76251 L 224.8861,498.36042 339.48636,384.26465 455.76603,265.15425 453.73057,84.870162 C 453.43979,62.916214 433.08513,46.632491 411.71274,51.284984 l -28.78729,6.251786 0.14539,-13.666697 C 383.36162,24.678542 365.62399,10.284894 347.01402,14.355825 Z"
sodipodi:nodetypes="ccssccccccccc"
style="stroke-width:1.45391" /><path
id="XMLID_117_"
class="st2"
d="m 383.21622,57.53677 v 285.8375 L 456.05681,265.00885 454.02135,78.763767 C 453.87595,59.863016 436.28372,45.905539 417.81914,49.97647 Z"
style="stroke-width:1.45391" /><polygon
id="XMLID_18_"
class="st3"
points="234.7,422.6 368.5,387.7 393.5,262.2 "
style="fill:url(#XMLID_5_)"
transform="matrix(1.4556308,0,0,1.4548265,-116.73161,-116.45231)" />
<linearGradient
id="XMLID_7_"
gradientUnits="userSpaceOnUse"
x1="223.0838"
y1="372.7559"
x2="241.4174"
y2="114.557"
gradientTransform="matrix(1.4539039,0,0,1.4539039,-116.19976,-116.20474)">
<stop
offset="0"
style="stop-color:#DCF1F3"
id="stop163" />
<stop
offset="1"
style="stop-color:#C2C2C9"
id="stop165" />
</linearGradient>
<path
id="XMLID_6_"
class="st4"
d="m 282.89686,214.84917 c 0,0 -22.24473,-28.93269 -38.67384,-36.78377 -10.46811,-4.94327 -26.02489,-6.83335 -38.23768,-0.72695 -18.02841,9.0142 -19.91848,34.31213 -3.34397,44.34406 3.92553,2.47165 9.15959,4.50711 15.99294,6.10641 36.63838,8.43264 97.12077,25.87949 89.70587,96.10304 0,0 -4.21633,65.86185 -73.56753,73.42215 -12.2128,1.30851 -24.57098,0.43617 -36.493,-2.32625 -16.42911,-3.63476 -45.50719,-11.04967 -59.75545,-19.91849 l -2.61703,-75.16682 h 6.97875 c 0,0 13.81208,33.43978 53.06749,49.57812 7.26952,2.90781 15.26599,4.07093 22.97168,2.90781 9.74116,-1.45391 21.22699,-6.68796 25.87949,-22.53551 0,0 7.85108,-23.11707 -32.85823,-35.76604 -32.56744,-10.17733 -63.24481,-20.64543 -75.89378,-54.95757 -5.961,-16.28371 -6.97874,-34.31212 -2.90781,-51.61358 5.37944,-22.53551 20.79082,-54.23062 64.40794,-67.89732 0,0 57.28381,-15.55677 96.53922,5.52484 l -1.74468,89.70587 z"
style="fill:url(#XMLID_7_);stroke-width:1.45391" />
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512" xml:space="preserve"><defs id="defs173"><linearGradient id="XMLID_5_" x1="304.496" x2="316.036" y1="422.91" y2="326.263" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#dcf1f3" id="stop156"/><stop offset="1" style="stop-color:#c2c2c9" id="stop158"/></linearGradient></defs><style id="style150" type="text/css">.st1{fill:#c02223}.st2{fill:#882425}.st3{fill:url(#XMLID_5_)}.st4{fill:url(#XMLID_7_)}</style><g id="XMLID_4_"><path id="XMLID_131_" d="M 347.01402,14.355825 98.978019,69.02261 C 73.825483,74.547445 55.942464,96.792175 55.942464,122.52628 v 315.06096 c 0,22.39012 16.719895,41.14548 38.819234,43.76251 L 224.8861,498.36042 339.48636,384.26465 455.76603,265.15425 453.73057,84.870162 C 453.43979,62.916214 433.08513,46.632491 411.71274,51.284984 l -28.78729,6.251786 0.14539,-13.666697 C 383.36162,24.678542 365.62399,10.284894 347.01402,14.355825 Z" class="st1" style="stroke-width:1.45391"/><path id="XMLID_117_" d="m 383.21622,57.53677 v 285.8375 L 456.05681,265.00885 454.02135,78.763767 C 453.87595,59.863016 436.28372,45.905539 417.81914,49.97647 Z" class="st2" style="stroke-width:1.45391"/><polygon id="XMLID_18_" points="234.7 422.6 368.5 387.7 393.5 262.2" class="st3" style="fill:url(#XMLID_5_)" transform="matrix(1.4556308,0,0,1.4548265,-116.73161,-116.45231)"/><linearGradient id="XMLID_7_" x1="223.084" x2="241.417" y1="372.756" y2="114.557" gradientTransform="matrix(1.4539039,0,0,1.4539039,-116.19976,-116.20474)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#dcf1f3" id="stop163"/><stop offset="1" style="stop-color:#c2c2c9" id="stop165"/></linearGradient><path id="XMLID_6_" d="m 282.89686,214.84917 c 0,0 -22.24473,-28.93269 -38.67384,-36.78377 -10.46811,-4.94327 -26.02489,-6.83335 -38.23768,-0.72695 -18.02841,9.0142 -19.91848,34.31213 -3.34397,44.34406 3.92553,2.47165 9.15959,4.50711 15.99294,6.10641 36.63838,8.43264 97.12077,25.87949 89.70587,96.10304 0,0 -4.21633,65.86185 -73.56753,73.42215 -12.2128,1.30851 -24.57098,0.43617 -36.493,-2.32625 -16.42911,-3.63476 -45.50719,-11.04967 -59.75545,-19.91849 l -2.61703,-75.16682 h 6.97875 c 0,0 13.81208,33.43978 53.06749,49.57812 7.26952,2.90781 15.26599,4.07093 22.97168,2.90781 9.74116,-1.45391 21.22699,-6.68796 25.87949,-22.53551 0,0 7.85108,-23.11707 -32.85823,-35.76604 -32.56744,-10.17733 -63.24481,-20.64543 -75.89378,-54.95757 -5.961,-16.28371 -6.97874,-34.31212 -2.90781,-51.61358 5.37944,-22.53551 20.79082,-54.23062 64.40794,-67.89732 0,0 57.28381,-15.55677 96.53922,5.52484 l -1.74468,89.70587 z" class="st4" style="fill:url(#XMLID_7_);stroke-width:1.45391"/></g></svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 KiB

After

Width:  |  Height:  |  Size: 242 KiB

View File

@@ -79,7 +79,9 @@ def write_readme(progress_list: list[tuple[str, int]]) -> None:
file.writelines(content)
def compare_files(default_file_path, file_paths, translation_status_file) -> list[tuple[str, int]]:
def compare_files(
default_file_path, file_paths, ignore_translation_file
) -> list[tuple[str, int]]:
"""Compares the default properties file with other
properties files in the directory.
@@ -92,18 +94,24 @@ def compare_files(default_file_path, file_paths, translation_status_file) -> lis
language and progress percentage.
""" # noqa: D205
num_lines = sum(
1 for line in open(default_file_path, encoding="utf-8") if line.strip() and not line.strip().startswith("#")
1
for line in open(default_file_path, encoding="utf-8")
if line.strip() and not line.strip().startswith("#")
)
result_list = []
sort_translation_status: tomlkit.TOMLDocument
sort_ignore_translation: tomlkit.TOMLDocument
# read toml
with open(translation_status_file, encoding="utf-8") as f:
sort_translation_status = tomlkit.parse(f.read())
with open(ignore_translation_file, encoding="utf-8") as f:
sort_ignore_translation = tomlkit.parse(f.read())
for file_path in file_paths:
language = os.path.basename(file_path).split("messages_", 1)[1].split(".properties", 1)[0]
language = (
os.path.basename(file_path)
.split("messages_", 1)[1]
.split(".properties", 1)[0]
)
fails = 0
if "en_GB" in language or "en_US" in language:
@@ -111,21 +119,25 @@ def compare_files(default_file_path, file_paths, translation_status_file) -> lis
result_list.append(("en_US", 100))
continue
if language not in sort_translation_status:
sort_translation_status[language] = tomlkit.table()
if language not in sort_ignore_translation:
sort_ignore_translation[language] = tomlkit.table()
if (
"ignore" not in sort_translation_status[language]
or len(sort_translation_status[language].get("ignore", [])) < 1
"ignore" not in sort_ignore_translation[language]
or len(sort_ignore_translation[language].get("ignore", [])) < 1
):
sort_translation_status[language]["ignore"] = tomlkit.array(["language.direction"])
sort_ignore_translation[language]["ignore"] = tomlkit.array(
["language.direction"]
)
# if "missing" not in sort_translation_status[language]:
# sort_translation_status[language]["missing"] = tomlkit.array()
# elif "language.direction" in sort_translation_status[language]["missing"]:
# sort_translation_status[language]["missing"].remove("language.direction")
# if "missing" not in sort_ignore_translation[language]:
# sort_ignore_translation[language]["missing"] = tomlkit.array()
# elif "language.direction" in sort_ignore_translation[language]["missing"]:
# sort_ignore_translation[language]["missing"].remove("language.direction")
with open(default_file_path, encoding="utf-8") as default_file, open(file_path, encoding="utf-8") as file:
with open(default_file_path, encoding="utf-8") as default_file, open(
file_path, encoding="utf-8"
) as file:
for _ in range(5):
next(default_file)
try:
@@ -133,34 +145,45 @@ def compare_files(default_file_path, file_paths, translation_status_file) -> lis
except StopIteration:
fails = num_lines
for line_num, (line_default, line_file) in enumerate(zip(default_file, file), start=6):
for line_num, (line_default, line_file) in enumerate(
zip(default_file, file), start=6
):
try:
# Ignoring empty lines and lines start with #
if line_default.strip() == "" or line_default.startswith("#"):
continue
default_key, default_value = line_default.split("=", 1)
file_key, file_value = line_file.split("=", 1)
if (
default_value.strip() == file_value.strip()
and default_key.strip() not in sort_translation_status[language]["ignore"]
and default_key.strip()
not in sort_ignore_translation[language]["ignore"]
):
print(f"{language}: Line {line_num} is missing the translation.")
# if default_key.strip() not in sort_translation_status[language]["missing"]:
print(
f"{language}: Line {line_num} is missing the translation."
)
# if default_key.strip() not in sort_ignore_translation[language]["missing"]:
# missing_array = tomlkit.array()
# missing_array.append(default_key.strip())
# missing_array.multiline(True)
# sort_translation_status[language]["missing"].extend(missing_array)
# sort_ignore_translation[language]["missing"].extend(missing_array)
fails += 1
# elif default_key.strip() in sort_translation_status[language]["ignore"]:
# if default_key.strip() in sort_translation_status[language]["missing"]:
# sort_translation_status[language]["missing"].remove(default_key.strip())
# elif default_key.strip() in sort_ignore_translation[language]["ignore"]:
# if default_key.strip() in sort_ignore_translation[language]["missing"]:
# sort_ignore_translation[language]["missing"].remove(default_key.strip())
if default_value.strip() != file_value.strip():
# if default_key.strip() in sort_translation_status[language]["missing"]:
# sort_translation_status[language]["missing"].remove(default_key.strip())
if default_key.strip() in sort_translation_status[language]["ignore"]:
sort_translation_status[language]["ignore"].remove(default_key.strip())
# if default_key.strip() in sort_ignore_translation[language]["missing"]:
# sort_ignore_translation[language]["missing"].remove(default_key.strip())
if (
default_key.strip()
in sort_ignore_translation[language]["ignore"]
):
sort_ignore_translation[language]["ignore"].remove(
default_key.strip()
)
except ValueError:
print(f"{line_default}|{line_file}")
exit(1)
except IndexError:
pass
@@ -171,9 +194,9 @@ def compare_files(default_file_path, file_paths, translation_status_file) -> lis
int((num_lines - fails) * 100 / num_lines),
)
)
translation_status = convert_to_multiline(sort_translation_status)
with open(translation_status_file, "w", encoding="utf-8") as file:
file.write(tomlkit.dumps(translation_status))
ignore_translation = convert_to_multiline(sort_ignore_translation)
with open(ignore_translation_file, "w", encoding="utf-8") as file:
file.write(tomlkit.dumps(ignore_translation))
unique_data = list(set(result_list))
unique_data.sort(key=lambda x: x[1], reverse=True)
@@ -187,6 +210,8 @@ if __name__ == "__main__":
reference_file = os.path.join(directory, "messages_en_GB.properties")
scripts_directory = os.path.join(os.getcwd(), "scripts")
translation_state_file = os.path.join(scripts_directory, "translation_status.toml")
translation_state_file = os.path.join(scripts_directory, "ignore_translation.toml")
write_readme(compare_files(reference_file, messages_file_paths, translation_state_file))
write_readme(
compare_files(reference_file, messages_file_paths, translation_state_file)
)

View File

@@ -10,7 +10,11 @@ ignore = [
[ca_CA]
ignore = [
'PDFToText.tags',
'adminUserSettings.admin',
'language.direction',
'survey.button',
'watermark.type.1',
]
[cs_CZ]
@@ -21,6 +25,11 @@ ignore = [
'text',
]
[da_DK]
ignore = [
'language.direction',
]
[de_DE]
ignore = [
'AddStampRequest.alphabet',
@@ -48,6 +57,7 @@ ignore = [
ignore = [
'adminUserSettings.roles',
'color',
'error',
'language.direction',
'no',
'showJS.tags',
@@ -60,8 +70,31 @@ ignore = [
[fr_FR]
ignore = [
'AddStampRequest.alphabet',
'AddStampRequest.position',
'AddStampRequest.rotation',
'PDFToBook.selectText.1',
'addPageNumbers.selectText.3',
'adminUserSettings.actions',
'alphabet',
'compare.document.1',
'compare.document.2',
'info',
'language.direction',
'licenses.license',
'licenses.module',
'licenses.nav',
'licenses.version',
'pdfOrganiser.mode',
'pipeline.title',
'pipelineOptions.pipelineHeader',
'sponsor',
'watermark.type.2',
]
[ga_IE]
ignore = [
'language.direction',
]
[hi_IN]
@@ -71,6 +104,7 @@ ignore = [
[hr_HR]
ignore = [
'PDFToBook.selectText.1',
'font',
'home.pipeline.title',
'info',
@@ -114,16 +148,34 @@ ignore = [
[nl_NL]
ignore = [
'HTMLToPDF.print',
'adjustContrast.contrast',
'compare.document.1',
'compare.document.2',
'error',
'getPdfInfo.downloadJson',
'help',
'info',
'language.direction',
'navbar.allTools',
'printFile.submit',
'showJS.downloadJS',
'sponsor',
]
[no_NB]
ignore = [
'PDFToBook.selectText.1',
'adminUserSettings.admin',
'info',
'language.direction',
'oops',
'sponsor',
]
[pl_PL]
ignore = [
'PDFToBook.selectText.1',
'language.direction',
]
@@ -149,12 +201,20 @@ ignore = [
[sk_SK]
ignore = [
'adminUserSettings.admin',
'home.multiTool.title',
'info',
'language.direction',
'navbar.sections.security',
'text',
'watermark.type.1',
]
[sr_LATN_RS]
ignore = [
'language.direction',
'licenses.version',
'poweredBy',
]
[sv_SE]
@@ -162,6 +222,14 @@ ignore = [
'language.direction',
]
[th_TH]
ignore = [
'language.direction',
'pipeline.title',
'pipelineOptions.pipelineHeader',
'showJS.tags',
]
[tr_TR]
ignore = [
'language.direction',
@@ -172,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

@@ -22,7 +22,8 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
"error",
"erroroauth",
"file",
"messageType");
"messageType",
"infoMessage");
@Override
public boolean preHandle(
@@ -31,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

@@ -4,17 +4,26 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.List;
import org.simpleyaml.configuration.comments.CommentType;
import org.simpleyaml.configuration.file.YamlFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
public class ConfigInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Logger logger = LoggerFactory.getLogger(ConfigInitializer.class);
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {
@@ -44,95 +53,89 @@ public class ConfigInitializer
}
}
} else {
// Path templatePath =
// Paths.get(
// getClass()
// .getClassLoader()
// .getResource("settings.yml.template")
// .toURI());
// Path userPath = Paths.get("configs", "settings.yml");
//
// List<String> templateLines = Files.readAllLines(templatePath);
// List<String> userLines =
// Files.exists(userPath) ? Files.readAllLines(userPath) : new
// ArrayList<>();
//
// List<String> resultLines = new ArrayList<>();
// int position = 0;
// for (String templateLine : templateLines) {
// // Check if the line is a comment
// if (templateLine.trim().startsWith("#")) {
// String entry = templateLine.trim().substring(1).trim();
// if (!entry.isEmpty()) {
// // Check if this comment has been uncommented in userLines
// String key = entry.split(":")[0].trim();
// addLine(resultLines, userLines, templateLine, key, position);
// } else {
// resultLines.add(templateLine);
// }
// }
// // Check if the line is a key-value pair
// else if (templateLine.contains(":")) {
// String key = templateLine.split(":")[0].trim();
// addLine(resultLines, userLines, templateLine, key, position);
// }
// // Handle empty lines
// else if (templateLine.trim().length() == 0) {
// resultLines.add("");
// }
// position++;
// }
//
// // Write the result to the user settings file
// Files.write(userPath, resultLines);
// Define the path to the config settings file
Path settingsPath = Paths.get("configs", "settings.yml");
// Load the template resource
URL settingsTemplateResource =
getClass().getClassLoader().getResource("settings.yml.template");
if (settingsTemplateResource == null) {
throw new IOException("Resource not found: settings.yml.template");
}
// Create a temporary file to copy the resource content
Path tempTemplatePath = Files.createTempFile("settings.yml", ".template");
try (InputStream in = settingsTemplateResource.openStream()) {
Files.copy(in, tempTemplatePath, StandardCopyOption.REPLACE_EXISTING);
}
final YamlFile settingsTemplateFile = new YamlFile(tempTemplatePath.toFile());
settingsTemplateFile.loadWithComments();
final YamlFile settingsFile = new YamlFile(settingsPath.toFile());
settingsFile.loadWithComments();
// Load headers and comments
String header = settingsTemplateFile.getHeader();
// Create a new file for temporary settings
final YamlFile tempSettingFile = new YamlFile(settingsPath.toFile());
tempSettingFile.createNewFile(true);
tempSettingFile.setHeader(header);
// Get all keys from the template
List<String> keys =
Arrays.asList(settingsTemplateFile.getKeys(true).toArray(new String[0]));
for (String key : keys) {
if (!key.contains(".")) {
// Add blank lines and comments to specific sections
tempSettingFile
.path(key)
.comment(settingsTemplateFile.getComment(key))
.blankLine();
continue;
}
// Copy settings from the template to the settings.yml file
changeConfigItemFromCommentToKeyValue(
settingsTemplateFile, settingsFile, tempSettingFile, key);
}
// Save the settings.yml file
tempSettingFile.save();
}
// Create custom settings file if it doesn't exist
Path customSettingsPath = Paths.get("configs", "custom_settings.yml");
if (!Files.exists(customSettingsPath)) {
Files.createFile(customSettingsPath);
}
}
// TODO check parent value instead of just indent lines for duplicate keys (like enabled etc)
private static void addLine(
List<String> resultLines,
List<String> userLines,
String templateLine,
String key,
int position) {
boolean added = false;
int templateIndentationLevel = getIndentationLevel(templateLine);
int pos = 0;
for (String settingsLine : userLines) {
if (settingsLine.trim().startsWith(key + ":") && position == pos) {
int settingsIndentationLevel = getIndentationLevel(settingsLine);
// Check if it is correct settingsLine and has the same parent as templateLine
if (settingsIndentationLevel == templateIndentationLevel) {
resultLines.add(settingsLine);
added = true;
break;
}
}
pos++;
private void changeConfigItemFromCommentToKeyValue(
final YamlFile settingsTemplateFile,
final YamlFile settingsFile,
final YamlFile tempSettingFile,
String path) {
if (settingsFile.get(path) == null && settingsTemplateFile.get(path) != null) {
// If the key is only in the template, add it to the temporary settings with comments
tempSettingFile
.path(path)
.set(settingsTemplateFile.get(path))
.comment(settingsTemplateFile.getComment(path, CommentType.BLOCK))
.commentSide(settingsTemplateFile.getComment(path, CommentType.SIDE));
} else if (settingsFile.get(path) != null && settingsTemplateFile.get(path) != null) {
// If the key is in both, update the temporary settings with the main settings' value
// and comments
tempSettingFile
.path(path)
.set(settingsFile.get(path))
.comment(settingsTemplateFile.getComment(path, CommentType.BLOCK))
.commentSide(settingsTemplateFile.getComment(path, CommentType.SIDE));
} else {
// Log if the key is not found in both YAML files
logger.info("Key not found in both YAML files: " + path);
}
if (!added) {
resultLines.add(templateLine);
}
}
private static int getIndentationLevel(String line) {
int indentationLevel = 0;
String trimmedLine = line.trim();
if (trimmedLine.startsWith("#")) {
line = trimmedLine.substring(1);
}
for (char c : line.toCharArray()) {
if (c == ' ') {
indentationLevel++;
} else {
break;
}
}
return indentationLevel;
}
}

View File

@@ -0,0 +1,16 @@
package stirling.software.SPDF.config;
import java.io.IOException;
import java.util.List;
import stirling.software.SPDF.utils.FileInfo;
public interface DatabaseBackupInterface {
void exportDatabase() throws IOException;
boolean importDatabase();
boolean hasBackup();
List<FileInfo> getBackupList();
}

View File

@@ -37,7 +37,8 @@ public class CustomAuthenticationSuccessHandler
: null;
if (savedRequest != null
&& !RequestUriUtils.isStaticResource(savedRequest.getRedirectUrl())) {
&& !RequestUriUtils.isStaticResource(
request.getContextPath(), savedRequest.getRedirectUrl())) {
// Redirect to the original destination
super.onAuthenticationSuccess(request, response, authentication);
} else {

View File

@@ -28,8 +28,10 @@ public class FirstLoginFilter extends OncePerRequestFilter {
throws ServletException, IOException {
String method = request.getMethod();
String requestURI = request.getRequestURI();
String contextPath = request.getContextPath();
// Check if the request is for static resources
boolean isStaticResource = RequestUriUtils.isStaticResource(requestURI);
boolean isStaticResource = RequestUriUtils.isStaticResource(contextPath, requestURI);
// If it's a static resource, just continue the filter chain and skip the logic below
if (isStaticResource) {
@@ -43,8 +45,8 @@ public class FirstLoginFilter extends OncePerRequestFilter {
if ("GET".equalsIgnoreCase(method)
&& user.isPresent()
&& user.get().isFirstLogin()
&& !"/change-creds".equals(requestURI)) {
response.sendRedirect(request.getContextPath() + "/change-creds");
&& !(contextPath + "/change-creds").equals(requestURI)) {
response.sendRedirect(contextPath + "/change-creds");
return;
}
}

View File

@@ -33,7 +33,8 @@ public class IPRateLimitingFilter implements Filter {
String method = httpRequest.getMethod();
String requestURI = httpRequest.getRequestURI();
// Check if the request is for static resources
boolean isStaticResource = RequestUriUtils.isStaticResource(requestURI);
boolean isStaticResource =
RequestUriUtils.isStaticResource(httpRequest.getContextPath(), requestURI);
// If it's a static resource, just continue the filter chain and skip the logic below
if (isStaticResource) {

View File

@@ -1,34 +1,38 @@
package stirling.software.SPDF.config.security;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.simpleyaml.configuration.file.YamlFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.DatabaseBackupInterface;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.Role;
@Component
@Slf4j
public class InitialSecuritySetup {
@Autowired private UserService userService;
@Autowired private ApplicationProperties applicationProperties;
private static final Logger logger = LoggerFactory.getLogger(InitialSecuritySetup.class);
@Autowired private DatabaseBackupInterface databaseBackupHelper;
@PostConstruct
public void init() {
if (!userService.hasUsers()) {
public void init() throws IllegalArgumentException, IOException {
if (databaseBackupHelper.hasBackup() && !userService.hasUsers()) {
databaseBackupHelper.importDatabase();
} else if (!userService.hasUsers()) {
initializeAdminUser();
} else {
databaseBackupHelper.exportDatabase();
}
initializeInternalApiUser();
}
@@ -42,12 +46,11 @@ public class InitialSecuritySetup {
}
}
private void initializeAdminUser() {
private void initializeAdminUser() throws IOException {
String initialUsername =
applicationProperties.getSecurity().getInitialLogin().getUsername();
String initialPassword =
applicationProperties.getSecurity().getInitialLogin().getPassword();
if (initialUsername != null
&& !initialUsername.isEmpty()
&& initialPassword != null
@@ -55,9 +58,9 @@ public class InitialSecuritySetup {
&& !userService.findByUsernameIgnoreCase(initialUsername).isPresent()) {
try {
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
logger.info("Admin user created: " + initialUsername);
log.info("Admin user created: " + initialUsername);
} catch (IllegalArgumentException e) {
logger.error("Failed to initialize security setup", e);
log.error("Failed to initialize security setup", e);
System.exit(1);
}
} else {
@@ -65,54 +68,38 @@ public class InitialSecuritySetup {
}
}
private void createDefaultAdminUser() {
private void createDefaultAdminUser() throws IllegalArgumentException, IOException {
String defaultUsername = "admin";
String defaultPassword = "stirling";
if (!userService.findByUsernameIgnoreCase(defaultUsername).isPresent()) {
userService.saveUser(defaultUsername, defaultPassword, Role.ADMIN.getRoleId(), true);
logger.info("Default admin user created: " + defaultUsername);
log.info("Default admin user created: " + defaultUsername);
}
}
private void initializeInternalApiUser() {
private void initializeInternalApiUser() throws IllegalArgumentException, IOException {
if (!userService.usernameExistsIgnoreCase(Role.INTERNAL_API_USER.getRoleId())) {
userService.saveUser(
Role.INTERNAL_API_USER.getRoleId(),
UUID.randomUUID().toString(),
Role.INTERNAL_API_USER.getRoleId());
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
logger.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
log.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
}
}
private void saveKeyToConfig(String key) throws IOException {
Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml
List<String> lines = Files.readAllLines(path);
boolean keyFound = false;
// Search for the existing key to replace it or place to add it
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).startsWith("AutomaticallyGenerated:")) {
keyFound = true;
if (i + 1 < lines.size() && lines.get(i + 1).trim().startsWith("key:")) {
lines.set(i + 1, " key: " + key);
break;
} else {
lines.add(i + 1, " key: " + key);
break;
}
}
}
final YamlFile settingsYml = new YamlFile(path.toFile());
// If the section doesn't exist, append it
if (!keyFound) {
lines.add("# Automatically Generated Settings (Do Not Edit Directly)");
lines.add("AutomaticallyGenerated:");
lines.add(" key: " + key);
}
settingsYml.loadWithComments();
// Write back to the file
Files.write(path, lines);
settingsYml
.path("AutomaticallyGenerated.key")
.set(key)
.comment("# Automatically Generated Settings (Do Not Edit Directly)");
settingsYml.save();
}
private boolean isValidUUID(String uuid) {

View File

@@ -38,12 +38,12 @@ import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationS
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2LogoutSuccessHandler;
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.GithubProvider;
import stirling.software.SPDF.model.ApplicationProperties.GoogleProvider;
import stirling.software.SPDF.model.ApplicationProperties.KeycloakProvider;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.provider.GithubProvider;
import stirling.software.SPDF.model.provider.GoogleProvider;
import stirling.software.SPDF.model.provider.KeycloakProvider;
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
@Configuration

View File

@@ -104,6 +104,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
contextPath + "/fonts/",
contextPath + "/js/",
contextPath + "/pdfjs/",
contextPath + "/pdfjs-legacy/",
contextPath + "/api/v1/info/status",
contextPath + "/site.webmanifest"
};

View File

@@ -19,7 +19,6 @@ import org.springframework.web.filter.OncePerRequestFilter;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.ConsumptionProbe;
import io.github.bucket4j.Refill;
import io.github.pixee.security.Newlines;
import jakarta.servlet.FilterChain;
@@ -142,7 +141,10 @@ public class UserBasedRateLimitingFilter extends OncePerRequestFilter {
private Bucket createUserBucket(int limitPerDay) {
Bandwidth limit =
Bandwidth.classic(limitPerDay, Refill.intervally(limitPerDay, Duration.ofDays(1)));
Bandwidth.builder()
.capacity(limitPerDay)
.refillIntervally(limitPerDay, Duration.ofDays(1))
.build();
return Bucket.builder().addLimit(limit).build();
}
}

View File

@@ -1,5 +1,6 @@
package stirling.software.SPDF.config.security;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -19,6 +20,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import stirling.software.SPDF.config.DatabaseBackupInterface;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.model.Authority;
@@ -38,8 +40,11 @@ public class UserService implements UserServiceInterface {
@Autowired private MessageSource messageSource;
@Autowired DatabaseBackupInterface databaseBackupHelper;
// Handle OAUTH2 login and user auto creation.
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) {
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
throws IllegalArgumentException, IOException {
if (!isUsernameValid(username)) {
return false;
}
@@ -131,7 +136,7 @@ public class UserService implements UserServiceInterface {
}
public void saveUser(String username, AuthenticationType authenticationType)
throws IllegalArgumentException {
throws IllegalArgumentException, IOException {
if (!isUsernameValid(username)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
@@ -142,9 +147,11 @@ public class UserService implements UserServiceInterface {
user.addAuthority(new Authority(Role.USER.getRoleId(), user));
user.setAuthenticationType(authenticationType);
userRepository.save(user);
databaseBackupHelper.exportDatabase();
}
public void saveUser(String username, String password) throws IllegalArgumentException {
public void saveUser(String username, String password)
throws IllegalArgumentException, IOException {
if (!isUsernameValid(username)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
@@ -154,10 +161,11 @@ public class UserService implements UserServiceInterface {
user.setEnabled(true);
user.setAuthenticationType(AuthenticationType.WEB);
userRepository.save(user);
databaseBackupHelper.exportDatabase();
}
public void saveUser(String username, String password, String role, boolean firstLogin)
throws IllegalArgumentException {
throws IllegalArgumentException, IOException {
if (!isUsernameValid(username)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
@@ -169,10 +177,11 @@ public class UserService implements UserServiceInterface {
user.setAuthenticationType(AuthenticationType.WEB);
user.setFirstLogin(firstLogin);
userRepository.save(user);
databaseBackupHelper.exportDatabase();
}
public void saveUser(String username, String password, String role)
throws IllegalArgumentException {
throws IllegalArgumentException, IOException {
saveUser(username, password, role, false);
}
@@ -206,7 +215,8 @@ public class UserService implements UserServiceInterface {
return userCount > 0;
}
public void updateUserSettings(String username, Map<String, String> updates) {
public void updateUserSettings(String username, Map<String, String> updates)
throws IOException {
Optional<User> userOpt = userRepository.findByUsernameIgnoreCase(username);
if (userOpt.isPresent()) {
User user = userOpt.get();
@@ -220,6 +230,7 @@ public class UserService implements UserServiceInterface {
user.setSettings(settingsMap);
userRepository.save(user);
databaseBackupHelper.exportDatabase();
}
}
@@ -235,22 +246,26 @@ public class UserService implements UserServiceInterface {
return authorityRepository.findByUserId(user.getId());
}
public void changeUsername(User user, String newUsername) throws IllegalArgumentException {
public void changeUsername(User user, String newUsername)
throws IllegalArgumentException, IOException {
if (!isUsernameValid(newUsername)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
user.setUsername(newUsername);
userRepository.save(user);
databaseBackupHelper.exportDatabase();
}
public void changePassword(User user, String newPassword) {
public void changePassword(User user, String newPassword) throws IOException {
user.setPassword(passwordEncoder.encode(newPassword));
userRepository.save(user);
databaseBackupHelper.exportDatabase();
}
public void changeFirstUse(User user, boolean firstUse) {
public void changeFirstUse(User user, boolean firstUse) throws IOException {
user.setFirstLogin(firstUse);
userRepository.save(user);
databaseBackupHelper.exportDatabase();
}
public void changeRole(User user, String newRole) {

View File

@@ -0,0 +1,205 @@
package stirling.software.SPDF.config.security.database;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
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;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.DatabaseBackupInterface;
import stirling.software.SPDF.utils.FileInfo;
@Slf4j
@Configuration
public class DatabaseBackupHelper implements DatabaseBackupInterface {
@Value("${spring.datasource.url}")
private String url;
private Path backupPath = Paths.get("configs/db/backup/");
@Override
public boolean hasBackup() {
// Check if there is at least one backup
return !getBackupList().isEmpty();
}
@Override
public List<FileInfo> getBackupList() {
// Check if the backup directory exists, and create it if it does not
ensureBackupDirectoryExists();
List<FileInfo> backupFiles = new ArrayList<>();
// Read the backup directory and filter for files with the prefix "backup_" and suffix
// ".sql"
try (DirectoryStream<Path> stream =
Files.newDirectoryStream(
backupPath,
path ->
path.getFileName().toString().startsWith("backup_")
&& path.getFileName().toString().endsWith(".sql"))) {
for (Path entry : stream) {
BasicFileAttributes attrs = Files.readAttributes(entry, BasicFileAttributes.class);
LocalDateTime modificationDate =
LocalDateTime.ofInstant(
attrs.lastModifiedTime().toInstant(), ZoneId.systemDefault());
LocalDateTime creationDate =
LocalDateTime.ofInstant(
attrs.creationTime().toInstant(), ZoneId.systemDefault());
long fileSize = attrs.size();
backupFiles.add(
new FileInfo(
entry.getFileName().toString(),
entry.toString(),
modificationDate,
fileSize,
creationDate));
}
} catch (IOException e) {
log.error("Error reading backup directory: {}", e.getMessage(), e);
}
return backupFiles;
}
// Imports a database backup from the specified file.
public boolean importDatabaseFromUI(String fileName) throws IOException {
return this.importDatabaseFromUI(getBackupFilePath(fileName));
}
// Imports a database backup from the specified path.
public boolean importDatabaseFromUI(Path tempTemplatePath) throws IOException {
boolean success = executeDatabaseScript(tempTemplatePath);
if (success) {
LocalDateTime dateNow = LocalDateTime.now();
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
Path insertOutputFilePath =
this.getBackupFilePath("backup_user_" + dateNow.format(myFormatObj) + ".sql");
Files.copy(tempTemplatePath, insertOutputFilePath);
Files.deleteIfExists(tempTemplatePath);
}
return success;
}
@Override
public boolean importDatabase() {
if (!this.hasBackup()) return false;
List<FileInfo> backupList = this.getBackupList();
backupList.sort(Comparator.comparing(FileInfo::getModificationDate).reversed());
return executeDatabaseScript(Paths.get(backupList.get(0).getFilePath()));
}
@Override
public void exportDatabase() throws IOException {
// Check if the backup directory exists, and create it if it does not
ensureBackupDirectoryExists();
// Filter and delete old backups if there are more than 5
List<FileInfo> filteredBackupList =
this.getBackupList().stream()
.filter(backup -> !backup.getFileName().startsWith("backup_user_"))
.collect(Collectors.toList());
if (filteredBackupList.size() > 5) {
filteredBackupList.sort(
Comparator.comparing(
p -> p.getFileName().substring(7, p.getFileName().length() - 4)));
Files.deleteIfExists(Paths.get(filteredBackupList.get(0).getFilePath()));
log.info("Deleted oldest backup: {}", filteredBackupList.get(0).getFileName());
}
LocalDateTime dateNow = LocalDateTime.now();
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
Path insertOutputFilePath =
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;";
try (Connection conn = DriverManager.getConnection(url, "sa", "");
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);
}
}
// Retrieves the H2 database version.
public String getH2Version() {
String version = "Unknown";
try (Connection conn = DriverManager.getConnection(url, "sa", "")) {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
if (rs.next()) {
version = rs.getString("version");
log.info("H2 Database Version: {}", version);
}
}
} catch (SQLException e) {
log.error("Error retrieving H2 version: {}", e.getMessage(), e);
}
return version;
}
// Deletes a backup file.
public boolean deleteBackupFile(String fileName) throws IOException {
Path filePath = this.getBackupFilePath(fileName);
if (Files.deleteIfExists(filePath)) {
log.info("Deleted backup file: {}", fileName);
return true;
} else {
log.error("File not found or could not be deleted: {}", fileName);
return false;
}
}
// Gets the Path object for a given backup file name.
public Path getBackupFilePath(String fileName) {
return Paths.get(backupPath.toString(), fileName);
}
private boolean executeDatabaseScript(Path scriptPath) {
String query = "RUNSCRIPT from ?;";
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) {
log.error("Error during database import: {}", e.getMessage(), e);
return false;
}
}
private void ensureBackupDirectoryExists() {
if (Files.notExists(backupPath)) {
try {
Files.createDirectories(backupPath);
} catch (IOException e) {
log.error("Error creating directories: {}", e.getMessage());
}
}
}
}

View File

@@ -0,0 +1,18 @@
package stirling.software.SPDF.config.security.database;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTasks {
@Autowired private DatabaseBackupHelper databaseBackupService;
@Scheduled(cron = "0 0 0 * * ?")
public void performBackup() throws IOException {
databaseBackupService.exportDatabase();
}
}

View File

@@ -48,13 +48,14 @@ public class CustomOAuth2AuthenticationSuccessHandler
// Get the saved request
HttpSession session = request.getSession(false);
String contextPath = request.getContextPath();
SavedRequest savedRequest =
(session != null)
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
: null;
if (savedRequest != null
&& !RequestUriUtils.isStaticResource(savedRequest.getRedirectUrl())) {
&& !RequestUriUtils.isStaticResource(contextPath, savedRequest.getRedirectUrl())) {
// Redirect to the original destination
super.onAuthenticationSuccess(request, response, authentication);
} else {
@@ -75,16 +76,15 @@ public class CustomOAuth2AuthenticationSuccessHandler
&& !userService.isAuthenticationTypeByUsername(
username, AuthenticationType.OAUTH2)
&& oAuth.getAutoCreateUser()) {
response.sendRedirect(
request.getContextPath() + "/logout?oauth2AuthenticationErrorWeb=true");
response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
return;
} else {
try {
userService.processOAuth2PostLogin(username, oAuth.getAutoCreateUser());
response.sendRedirect("/");
response.sendRedirect(contextPath + "/");
return;
} catch (IllegalArgumentException e) {
response.sendRedirect("/logout?invalidUsername=true");
response.sendRedirect(contextPath + "/logout?invalidUsername=true");
return;
}
}

View File

@@ -16,6 +16,7 @@ import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.Provider;
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
import stirling.software.SPDF.utils.UrlUtils;
public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@@ -51,8 +52,8 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
Provider provider = oauth.getClient().get(registrationId);
issuer = provider.getIssuer();
clientId = provider.getClientId();
} catch (Exception e) {
logger.error("exception", e);
} catch (UnsupportedProviderException e) {
logger.error(e.getMessage());
}
} else {

View File

@@ -0,0 +1,144 @@
package stirling.software.SPDF.controller.api;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.eclipse.jetty.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.database.DatabaseBackupHelper;
@Slf4j
@Controller
@RequestMapping("/api/v1/database")
@PreAuthorize("hasRole('ROLE_ADMIN')")
@Tag(name = "Database", description = "Database APIs")
public class DatabaseController {
@Autowired DatabaseBackupHelper databaseBackupHelper;
@Hidden
@PostMapping(consumes = "multipart/form-data", value = "import-database")
@Operation(
summary = "Import database backup",
description = "This endpoint imports a database backup from a SQL file.")
public String importDatabase(
@RequestParam("fileInput") MultipartFile file, RedirectAttributes redirectAttributes)
throws IllegalArgumentException, IOException {
if (file == null || file.isEmpty()) {
redirectAttributes.addAttribute("error", "fileNullOrEmpty");
return "redirect:/database";
}
log.info("Received file: {}", file.getOriginalFilename());
Path tempTemplatePath = Files.createTempFile("backup_", ".sql");
try (InputStream in = file.getInputStream()) {
Files.copy(in, tempTemplatePath, StandardCopyOption.REPLACE_EXISTING);
boolean importSuccess = databaseBackupHelper.importDatabaseFromUI(tempTemplatePath);
if (importSuccess) {
redirectAttributes.addAttribute("infoMessage", "importIntoDatabaseSuccessed");
} else {
redirectAttributes.addAttribute("error", "failedImportFile");
}
} catch (Exception e) {
log.error("Error importing database: {}", e.getMessage());
redirectAttributes.addAttribute("error", "failedImportFile");
}
return "redirect:/database";
}
@Hidden
@GetMapping("/import-database-file/{fileName}")
public String importDatabaseFromBackupUI(@PathVariable String fileName)
throws IllegalArgumentException, IOException {
if (fileName == null || fileName.isEmpty()) {
return "redirect:/database?error=fileNullOrEmpty";
}
// Check if the file exists in the backup list
boolean fileExists =
databaseBackupHelper.getBackupList().stream()
.anyMatch(backup -> backup.getFileName().equals(fileName));
if (!fileExists) {
log.error("File {} not found in backup list", fileName);
return "redirect:/database?error=fileNotFound";
}
log.info("Received file: {}", fileName);
if (databaseBackupHelper.importDatabaseFromUI(fileName)) {
log.info("File {} imported to database", fileName);
return "redirect:/database?infoMessage=importIntoDatabaseSuccessed";
}
return "redirect:/database?error=failedImportFile";
}
@Hidden
@GetMapping("/delete/{fileName}")
@Operation(
summary = "Delete a database backup file",
description =
"This endpoint deletes a database backup file with the specified file name.")
public String deleteFile(@PathVariable String fileName) {
if (fileName == null || fileName.isEmpty()) {
throw new IllegalArgumentException("File must not be null or empty");
}
try {
if (databaseBackupHelper.deleteBackupFile(fileName)) {
log.info("Deleted file: {}", fileName);
} else {
log.error("Failed to delete file: {}", fileName);
return "redirect:/database?error=failedToDeleteFile";
}
} catch (IOException e) {
log.error("Error deleting file: {}", e.getMessage());
return "redirect:/database?error=" + e.getMessage();
}
return "redirect:/database";
}
@Hidden
@GetMapping("/download/{fileName}")
@Operation(
summary = "Download a database backup file",
description =
"This endpoint downloads a database backup file with the specified file name.")
public ResponseEntity<?> downloadFile(@PathVariable String fileName) {
if (fileName == null || fileName.isEmpty()) {
throw new IllegalArgumentException("File must not be null or empty");
}
try {
Path filePath = databaseBackupHelper.getBackupFilePath(fileName);
InputStreamResource resource = new InputStreamResource(Files.newInputStream(filePath));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(Files.size(filePath))
.body(resource);
} catch (IOException e) {
log.error("Error downloading file: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.SEE_OTHER_303)
.location(URI.create("/database?error=downloadFailed"))
.build();
}
}
}

View File

@@ -145,6 +145,28 @@ public class RearrangePagesPDFController {
return newPageOrder;
}
/**
* Rearrange pages in a PDF file by merging odd and even pages. The first half of the pages will
* be the odd pages, and the second half will be the even pages as input. <br>
* This method is visible for testing purposes only.
*
* @param totalPages Total number of pages in the PDF file.
* @return List of page numbers in the new order. The first page is 0.
*/
List<Integer> oddEvenMerge(int totalPages) {
List<Integer> newPageOrderZeroBased = new ArrayList<>();
int numberOfOddPages = (totalPages + 1) / 2;
for (int oneBasedIndex = 1; oneBasedIndex < (numberOfOddPages + 1); oneBasedIndex++) {
newPageOrderZeroBased.add((oneBasedIndex - 1));
if (numberOfOddPages + oneBasedIndex <= totalPages) {
newPageOrderZeroBased.add((numberOfOddPages + oneBasedIndex - 1));
}
}
return newPageOrderZeroBased;
}
private List<Integer> processSortTypes(String sortTypes, int totalPages) {
try {
SortTypes mode = SortTypes.valueOf(sortTypes.toUpperCase());
@@ -159,6 +181,8 @@ public class RearrangePagesPDFController {
return sideStitchBooklet(totalPages);
case ODD_EVEN_SPLIT:
return oddEvenSplit(totalPages);
case ODD_EVEN_MERGE:
return oddEvenMerge(totalPages);
case REMOVE_FIRST:
return removeFirst(totalPages);
case REMOVE_LAST:

View File

@@ -1,5 +1,6 @@
package stirling.software.SPDF.controller.api;
import java.io.IOException;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
@@ -42,7 +43,8 @@ public class UserController {
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/register")
public String register(@ModelAttribute UsernameAndPass requestModel, Model model) {
public String register(@ModelAttribute UsernameAndPass requestModel, Model model)
throws IOException {
if (userService.usernameExistsIgnoreCase(requestModel.getUsername())) {
model.addAttribute("error", "Username already exists");
return "register";
@@ -59,11 +61,12 @@ public class UserController {
@PostMapping("/change-username")
public RedirectView changeUsername(
Principal principal,
@RequestParam(name = "currentPassword") String currentPassword,
@RequestParam(name = "currentPasswordChangeUsername") String currentPassword,
@RequestParam(name = "newUsername") String newUsername,
HttpServletRequest request,
HttpServletResponse response,
RedirectAttributes redirectAttributes) {
RedirectAttributes redirectAttributes)
throws IOException {
if (!userService.isUsernameValid(newUsername)) {
return new RedirectView("/account?messageType=invalidUsername", true);
@@ -116,7 +119,8 @@ public class UserController {
@RequestParam(name = "newPassword") String newPassword,
HttpServletRequest request,
HttpServletResponse response,
RedirectAttributes redirectAttributes) {
RedirectAttributes redirectAttributes)
throws IOException {
if (principal == null) {
return new RedirectView("/change-creds?messageType=notAuthenticated", true);
}
@@ -149,7 +153,8 @@ public class UserController {
@RequestParam(name = "newPassword") String newPassword,
HttpServletRequest request,
HttpServletResponse response,
RedirectAttributes redirectAttributes) {
RedirectAttributes redirectAttributes)
throws IOException {
if (principal == null) {
return new RedirectView("/account?messageType=notAuthenticated", true);
}
@@ -176,7 +181,8 @@ public class UserController {
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/updateUserSettings")
public String updateUserSettings(HttpServletRequest request, Principal principal) {
public String updateUserSettings(HttpServletRequest request, Principal principal)
throws IOException {
Map<String, String[]> paramMap = request.getParameterMap();
Map<String, String> updates = new HashMap<>();
@@ -201,7 +207,8 @@ public class UserController {
@RequestParam(name = "password") String password,
@RequestParam(name = "role") String role,
@RequestParam(name = "forceChange", required = false, defaultValue = "false")
boolean forceChange) {
boolean forceChange)
throws IllegalArgumentException, IOException {
if (!userService.isUsernameValid(username)) {
return new RedirectView("/addUsers?messageType=invalidUsername", true);

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

@@ -24,14 +24,14 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.GithubProvider;
import stirling.software.SPDF.model.ApplicationProperties.GoogleProvider;
import stirling.software.SPDF.model.ApplicationProperties.KeycloakProvider;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.SPDF.model.Authority;
import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.provider.GithubProvider;
import stirling.software.SPDF.model.provider.GoogleProvider;
import stirling.software.SPDF.model.provider.KeycloakProvider;
import stirling.software.SPDF.repository.UserRepository;
@Controller
@@ -43,6 +43,7 @@ public class AccountWebController {
@GetMapping("/login")
public String login(HttpServletRequest request, Model model, Authentication authentication) {
if (authentication != null && authentication.isAuthenticated()) {
return "redirect:/";
}
@@ -72,8 +73,13 @@ public class AccountWebController {
}
}
}
// Remove any null keys/values from the providerList
providerList
.entrySet()
.removeIf(entry -> entry.getKey() == null || entry.getValue() == null);
model.addAttribute("providerlist", providerList);
model.addAttribute("loginMethod", applicationProperties.getSecurity().getLoginMethod());
model.addAttribute(
"oAuth2Enabled", applicationProperties.getSecurity().getOAUTH2().getEnabled());

View File

@@ -0,0 +1,41 @@
package stirling.software.SPDF.controller.web;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import stirling.software.SPDF.config.security.database.DatabaseBackupHelper;
import stirling.software.SPDF.utils.FileInfo;
@Controller
@Tag(name = "Database Management", description = "Database management and security APIs")
public class DatabaseWebController {
@Autowired private DatabaseBackupHelper databaseBackupHelper;
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/database")
public String database(HttpServletRequest request, Model model, Authentication authentication) {
String error = request.getParameter("error");
String confirmed = request.getParameter("infoMessage");
if (error != null) {
model.addAttribute("error", error);
} else if (confirmed != null) {
model.addAttribute("infoMessage", confirmed);
}
List<FileInfo> backupList = databaseBackupHelper.getBackupList();
model.addAttribute("systemUpdate", backupList);
return "database";
}
}

View File

@@ -13,6 +13,10 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import stirling.software.SPDF.config.YamlPropertySourceFactory;
import stirling.software.SPDF.model.provider.GithubProvider;
import stirling.software.SPDF.model.provider.GoogleProvider;
import stirling.software.SPDF.model.provider.KeycloakProvider;
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
@Configuration
@ConfigurationProperties(prefix = "")
@@ -128,6 +132,15 @@ public class ApplicationProperties {
private OAUTH2 oauth2;
private int loginAttemptCount;
private long loginResetTimeMinutes;
private String loginMethod = "all";
public String getLoginMethod() {
return loginMethod;
}
public void setLoginMethod(String loginMethod) {
this.loginMethod = loginMethod;
}
public int getLoginAttemptCount() {
return loginAttemptCount;
@@ -187,6 +200,8 @@ public class ApplicationProperties {
+ initialLogin
+ ", csrfDisabled="
+ csrfDisabled
+ ", loginMethod="
+ loginMethod
+ "]";
}
@@ -345,6 +360,8 @@ public class ApplicationProperties {
+ useAsUsername
+ ", provider="
+ provider
+ ", client="
+ client
+ ", scopes="
+ scopes
+ "]";
@@ -355,7 +372,7 @@ public class ApplicationProperties {
private GithubProvider github = new GithubProvider();
private KeycloakProvider keycloak = new KeycloakProvider();
public Provider get(String registrationId) throws Exception {
public Provider get(String registrationId) throws UnsupportedProviderException {
switch (registrationId.toLowerCase()) {
case "google":
return getGoogle();
@@ -366,7 +383,8 @@ public class ApplicationProperties {
default:
break;
}
throw new Exception("Provider not supported, use custom setting.");
throw new UnsupportedProviderException(
"Logout from the provider is not supported? Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues");
}
public GoogleProvider getGoogle() {
@@ -407,311 +425,6 @@ public class ApplicationProperties {
}
}
public static class GoogleProvider extends Provider {
private static final String authorizationUri =
"https://accounts.google.com/o/oauth2/v2/auth";
private static final String tokenUri = "https://www.googleapis.com/oauth2/v4/token";
private static final String userInfoUri =
"https://www.googleapis.com/oauth2/v3/userinfo?alt=json";
public String getAuthorizationuri() {
return authorizationUri;
}
public String getTokenuri() {
return tokenUri;
}
public String getUserinfouri() {
return userInfoUri;
}
private String clientId;
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "email";
@Override
public String getClientId() {
return this.clientId;
}
@Override
public void setClientId(String clientId) {
this.clientId = clientId;
}
@Override
public String getClientSecret() {
return this.clientSecret;
}
@Override
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@Override
public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("https://www.googleapis.com/auth/userinfo.email");
scopes.add("https://www.googleapis.com/auth/userinfo.profile");
}
return scopes;
}
@Override
public void setScopes(String scopes) {
this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
}
@Override
public String getUseAsUsername() {
return this.useAsUsername;
}
@Override
public void setUseAsUsername(String useAsUsername) {
this.useAsUsername = useAsUsername;
}
@Override
public String toString() {
return "Google [clientId="
+ clientId
+ ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
+ ", scopes="
+ scopes
+ ", useAsUsername="
+ useAsUsername
+ "]";
}
@Override
public String getName() {
return "google";
}
@Override
public String getClientName() {
return "Google";
}
public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret")
&& super.isValid(this.getScopes(), "scopes")
&& isValid(this.getUseAsUsername(), "useAsUsername");
}
}
public static class GithubProvider extends Provider {
private static final String authorizationUri = "https://github.com/login/oauth/authorize";
private static final String tokenUri = "https://github.com/login/oauth/access_token";
private static final String userInfoUri = "https://api.github.com/user";
public String getAuthorizationuri() {
return authorizationUri;
}
public String getTokenuri() {
return tokenUri;
}
public String getUserinfouri() {
return userInfoUri;
}
private String clientId;
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "login";
@Override
public String getIssuer() {
return new String();
}
@Override
public void setIssuer(String issuer) {}
@Override
public String getClientId() {
return this.clientId;
}
@Override
public void setClientId(String clientId) {
this.clientId = clientId;
}
@Override
public String getClientSecret() {
return this.clientSecret;
}
@Override
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@Override
public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("read:user");
}
return scopes;
}
@Override
public void setScopes(String scopes) {
this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
}
@Override
public String getUseAsUsername() {
return this.useAsUsername;
}
@Override
public void setUseAsUsername(String useAsUsername) {
this.useAsUsername = useAsUsername;
}
@Override
public String toString() {
return "GitHub [clientId="
+ clientId
+ ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
+ ", scopes="
+ scopes
+ ", useAsUsername="
+ useAsUsername
+ "]";
}
@Override
public String getName() {
return "github";
}
@Override
public String getClientName() {
return "GitHub";
}
public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret")
&& super.isValid(this.getScopes(), "scopes")
&& isValid(this.getUseAsUsername(), "useAsUsername");
}
}
public static class KeycloakProvider extends Provider {
private String issuer;
private String clientId;
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "email";
@Override
public String getIssuer() {
return this.issuer;
}
@Override
public void setIssuer(String issuer) {
this.issuer = issuer;
}
@Override
public String getClientId() {
return this.clientId;
}
@Override
public void setClientId(String clientId) {
this.clientId = clientId;
}
@Override
public String getClientSecret() {
return this.clientSecret;
}
@Override
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@Override
public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("profile");
scopes.add("email");
}
return scopes;
}
@Override
public void setScopes(String scopes) {
this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
}
@Override
public String getUseAsUsername() {
return this.useAsUsername;
}
@Override
public void setUseAsUsername(String useAsUsername) {
this.useAsUsername = useAsUsername;
}
@Override
public String toString() {
return "Keycloak [issuer="
+ issuer
+ ", clientId="
+ clientId
+ ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
+ ", scopes="
+ scopes
+ ", useAsUsername="
+ useAsUsername
+ "]";
}
@Override
public String getName() {
return "keycloak";
}
@Override
public String getClientName() {
return "Keycloak";
}
public boolean isSettingsValid() {
return isValid(this.getIssuer(), "issuer")
&& isValid(this.getClientId(), "clientId")
&& isValid(this.getClientSecret(), "clientSecret")
&& isValid(this.getScopes(), "scopes")
&& isValid(this.getUseAsUsername(), "useAsUsername");
}
}
public static class System {
private String defaultLocale;
private Boolean googlevisibility;

View File

@@ -6,6 +6,7 @@ public enum SortTypes {
BOOKLET_SORT,
SIDE_STITCH_BOOKLET_SORT,
ODD_EVEN_SPLIT,
ODD_EVEN_MERGE,
REMOVE_FIRST,
REMOVE_LAST,
REMOVE_FIRST_AND_LAST,

View File

@@ -16,6 +16,7 @@ import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.Lob;
import jakarta.persistence.MapKeyColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
@@ -55,7 +56,8 @@ public class User {
@ElementCollection
@MapKeyColumn(name = "setting_key")
@Column(name = "setting_value")
@Lob
@Column(name = "setting_value", columnDefinition = "CLOB")
@CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id"))
private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings.

View File

@@ -19,6 +19,7 @@ public class RearrangePagesRequest extends PDFWithPageNums {
+ "DUPLEX_SORT: Sorts pages as if all fronts were scanned then all backs in reverse (1, n, 2, n-1, ...). "
+ "BOOKLET_SORT: Arranges pages for booklet printing (last, first, second, second last, ...).\n"
+ "ODD_EVEN_SPLIT: Splits and arranges pages into odd and even numbered pages.\n"
+ "ODD_EVEN_MERGE: Merges pages and organises them alternately into odd and even pages.\n"
+ "REMOVE_FIRST: Removes the first page.\n"
+ "REMOVE_LAST: Removes the last page.\n"
+ "REMOVE_FIRST_AND_LAST: Removes both the first and the last pages.\n")

View File

@@ -0,0 +1,115 @@
package stirling.software.SPDF.model.provider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import stirling.software.SPDF.model.Provider;
public class GithubProvider extends Provider {
private static final String authorizationUri = "https://github.com/login/oauth/authorize";
private static final String tokenUri = "https://github.com/login/oauth/access_token";
private static final String userInfoUri = "https://api.github.com/user";
public String getAuthorizationuri() {
return authorizationUri;
}
public String getTokenuri() {
return tokenUri;
}
public String getUserinfouri() {
return userInfoUri;
}
private String clientId;
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "login";
@Override
public String getIssuer() {
return new String();
}
@Override
public void setIssuer(String issuer) {}
@Override
public String getClientId() {
return this.clientId;
}
@Override
public void setClientId(String clientId) {
this.clientId = clientId;
}
@Override
public String getClientSecret() {
return this.clientSecret;
}
@Override
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@Override
public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("read:user");
}
return scopes;
}
@Override
public void setScopes(String scopes) {
this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
}
@Override
public String getUseAsUsername() {
return this.useAsUsername;
}
@Override
public void setUseAsUsername(String useAsUsername) {
this.useAsUsername = useAsUsername;
}
@Override
public String toString() {
return "GitHub [clientId="
+ clientId
+ ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
+ ", scopes="
+ scopes
+ ", useAsUsername="
+ useAsUsername
+ "]";
}
@Override
public String getName() {
return "github";
}
@Override
public String getClientName() {
return "GitHub";
}
public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret")
&& super.isValid(this.getScopes(), "scopes")
&& isValid(this.getUseAsUsername(), "useAsUsername");
}
}

View File

@@ -0,0 +1,109 @@
package stirling.software.SPDF.model.provider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import stirling.software.SPDF.model.Provider;
public class GoogleProvider extends Provider {
private static final String authorizationUri = "https://accounts.google.com/o/oauth2/v2/auth";
private static final String tokenUri = "https://www.googleapis.com/oauth2/v4/token";
private static final String userInfoUri =
"https://www.googleapis.com/oauth2/v3/userinfo?alt=json";
public String getAuthorizationuri() {
return authorizationUri;
}
public String getTokenuri() {
return tokenUri;
}
public String getUserinfouri() {
return userInfoUri;
}
private String clientId;
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "email";
@Override
public String getClientId() {
return this.clientId;
}
@Override
public void setClientId(String clientId) {
this.clientId = clientId;
}
@Override
public String getClientSecret() {
return this.clientSecret;
}
@Override
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@Override
public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("https://www.googleapis.com/auth/userinfo.email");
scopes.add("https://www.googleapis.com/auth/userinfo.profile");
}
return scopes;
}
@Override
public void setScopes(String scopes) {
this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
}
@Override
public String getUseAsUsername() {
return this.useAsUsername;
}
@Override
public void setUseAsUsername(String useAsUsername) {
this.useAsUsername = useAsUsername;
}
@Override
public String toString() {
return "Google [clientId="
+ clientId
+ ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
+ ", scopes="
+ scopes
+ ", useAsUsername="
+ useAsUsername
+ "]";
}
@Override
public String getName() {
return "google";
}
@Override
public String getClientName() {
return "Google";
}
public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret")
&& super.isValid(this.getScopes(), "scopes")
&& isValid(this.getUseAsUsername(), "useAsUsername");
}
}

View File

@@ -0,0 +1,106 @@
package stirling.software.SPDF.model.provider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import stirling.software.SPDF.model.Provider;
public class KeycloakProvider extends Provider {
private String issuer;
private String clientId;
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "email";
@Override
public String getIssuer() {
return this.issuer;
}
@Override
public void setIssuer(String issuer) {
this.issuer = issuer;
}
@Override
public String getClientId() {
return this.clientId;
}
@Override
public void setClientId(String clientId) {
this.clientId = clientId;
}
@Override
public String getClientSecret() {
return this.clientSecret;
}
@Override
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@Override
public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("profile");
scopes.add("email");
}
return scopes;
}
@Override
public void setScopes(String scopes) {
this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
}
@Override
public String getUseAsUsername() {
return this.useAsUsername;
}
@Override
public void setUseAsUsername(String useAsUsername) {
this.useAsUsername = useAsUsername;
}
@Override
public String toString() {
return "Keycloak [issuer="
+ issuer
+ ", clientId="
+ clientId
+ ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
+ ", scopes="
+ scopes
+ ", useAsUsername="
+ useAsUsername
+ "]";
}
@Override
public String getName() {
return "keycloak";
}
@Override
public String getClientName() {
return "Keycloak";
}
public boolean isSettingsValid() {
return isValid(this.getIssuer(), "issuer")
&& isValid(this.getClientId(), "clientId")
&& isValid(this.getClientSecret(), "clientSecret")
&& isValid(this.getScopes(), "scopes")
&& isValid(this.getUseAsUsername(), "useAsUsername");
}
}

View File

@@ -0,0 +1,7 @@
package stirling.software.SPDF.model.provider;
public class UnsupportedProviderException extends Exception {
public UnsupportedProviderException(String message) {
super(message);
}
}

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

@@ -0,0 +1,50 @@
package stirling.software.SPDF.utils;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class FileInfo {
private String fileName;
private String filePath;
private LocalDateTime modificationDate;
private long fileSize;
private LocalDateTime creationDate;
private static final DateTimeFormatter DATE_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// Converts the file path string to a Path object.
public Path getFilePathAsPath() {
return Paths.get(filePath);
}
// Formats the file size into a human-readable string.
public String getFormattedFileSize() {
if (fileSize >= 1024 * 1024 * 1024) {
return String.format("%.2f GB", fileSize / (1024.0 * 1024 * 1024));
} else if (fileSize >= 1024 * 1024) {
return String.format("%.2f MB", fileSize / (1024.0 * 1024));
} else if (fileSize >= 1024) {
return String.format("%.2f KB", fileSize / 1024.0);
} else {
return String.format("%d Bytes", fileSize);
}
}
// Formats the modification date to a string.
public String getFormattedModificationDate() {
return modificationDate.format(DATE_FORMATTER);
}
// Formats the creation date to a string.
public String getFormattedCreationDate() {
return creationDate.format(DATE_FORMATTER);
}
}

View File

@@ -140,6 +140,8 @@ public class PDFToFile {
new ArrayList<>(
Arrays.asList(
"soffice",
"--headless",
"--nologo",
"--infilter=" + libreOfficeFilter,
"--convert-to",
outputFormat,

View File

@@ -1,27 +1,27 @@
package stirling.software.SPDF.utils;
import java.awt.Graphics;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.*;
import javax.imageio.stream.ImageOutputStream;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
@@ -245,19 +245,64 @@ public class PdfUtils {
writer.dispose();
} else {
// Combine all images into a single big image
BufferedImage image = pdfRenderer.renderImageWithDPI(0, DPI, colorType);
// Calculate the combined image dimensions
int maxWidth = 0;
int totalHeight = 0;
BufferedImage pdfSizeImage = null;
int pdfSizeImageIndex = -1;
// Using a map to store the rendered dimensions of each page size
// to avoid rendering the same page sizes multiple times
HashMap<PdfRenderSettingsKey, PdfImageDimensionValue> pageSizes =
new HashMap<>();
for (int i = 0; i < pageCount; ++i) {
PDPage page = document.getPage(i);
PDRectangle mediaBox = page.getMediaBox();
int rotation = page.getRotation();
PdfRenderSettingsKey settings =
new PdfRenderSettingsKey(
mediaBox.getWidth(), mediaBox.getHeight(), rotation);
PdfImageDimensionValue dimension = pageSizes.get(settings);
if (dimension == null) {
// Render the image to get the dimensions
pdfSizeImage = pdfRenderer.renderImageWithDPI(i, DPI, colorType);
pdfSizeImageIndex = i;
dimension =
new PdfImageDimensionValue(
pdfSizeImage.getWidth(), pdfSizeImage.getHeight());
pageSizes.put(settings, dimension);
if (pdfSizeImage.getWidth() > maxWidth) {
maxWidth = pdfSizeImage.getWidth();
}
}
totalHeight += dimension.height();
}
// Create a new BufferedImage to store the combined images
BufferedImage combined =
new BufferedImage(
image.getWidth(),
image.getHeight() * pageCount,
BufferedImage.TYPE_INT_RGB);
prepareImageForPdfToImage(maxWidth, totalHeight, imageType);
Graphics g = combined.getGraphics();
int currentHeight = 0;
BufferedImage pageImage;
// Check if the first image is the last rendered image
boolean firstImageAlreadyRendered = pdfSizeImageIndex == 0;
for (int i = 0; i < pageCount; ++i) {
if (i != 0) {
image = pdfRenderer.renderImageWithDPI(i, DPI, colorType);
if (firstImageAlreadyRendered && i == 0) {
pageImage = pdfSizeImage;
} else {
pageImage = pdfRenderer.renderImageWithDPI(i, DPI, colorType);
}
g.drawImage(image, 0, i * image.getHeight(), null);
// Calculate the x-coordinate to center the image
int x = (maxWidth - pageImage.getWidth()) / 2;
g.drawImage(pageImage, x, currentHeight, null);
currentHeight += pageImage.getHeight();
}
// Write the image to the output stream
@@ -296,6 +341,23 @@ public class PdfUtils {
}
}
private static BufferedImage prepareImageForPdfToImage(
int maxWidth, int height, String imageType) {
BufferedImage combined;
if ("png".equalsIgnoreCase(imageType)) {
combined = new BufferedImage(maxWidth, height, BufferedImage.TYPE_INT_ARGB);
} else {
combined = new BufferedImage(maxWidth, height, BufferedImage.TYPE_INT_RGB);
}
if (!"png".equalsIgnoreCase(imageType)) {
Graphics g = combined.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, combined.getWidth(), combined.getHeight());
g.dispose();
}
return combined;
}
public static byte[] imageToPdf(
MultipartFile[] files, String fitOption, boolean autoRotate, String colorType)
throws IOException {
@@ -443,4 +505,10 @@ public class PdfUtils {
pdf.getDocumentInformation().setCreationDate(pdfMetadata.getCreationDate());
pdf.getDocumentInformation().setModificationDate(Calendar.getInstance());
}
/** Key for storing the dimensions of a rendered image in a map. */
private record PdfRenderSettingsKey(float mediaBoxWidth, float mediaBoxHeight, int rotation) {}
/** Value for storing the dimensions of a rendered image in a map. */
private record PdfImageDimensionValue(int width, int height) {}
}

View File

@@ -10,7 +10,22 @@ public class RequestUriUtils {
|| requestURI.startsWith("/images/")
|| requestURI.startsWith("/public/")
|| requestURI.startsWith("/pdfjs/")
|| requestURI.startsWith("/pdfjs-legacy/")
|| requestURI.endsWith(".svg")
|| requestURI.endsWith(".webmanifest")
|| requestURI.startsWith("/api/v1/info/status");
}
public static boolean isStaticResource(String contextPath, String requestURI) {
return requestURI.startsWith(contextPath + "/css/")
|| requestURI.startsWith(contextPath + "/fonts/")
|| requestURI.startsWith(contextPath + "/js/")
|| requestURI.startsWith(contextPath + "/images/")
|| requestURI.startsWith(contextPath + "/public/")
|| requestURI.startsWith(contextPath + "/pdfjs/")
|| requestURI.endsWith(".svg")
|| requestURI.endsWith(".webmanifest")
|| requestURI.startsWith(contextPath + "/api/v1/info/status");
}
}

View File

@@ -21,7 +21,7 @@ saveToBrowser=Save to Browser
close=إغلاق
filesSelected=الملفات المحددة
noFavourites=لم تتم إضافة أي مفضلات
downloadComplete=Download Complete
downloadComplete=إكتمل التحميل
bored=الانتظار بالملل؟
alphabet=الأبجدية
downloadPdf=تنزيل PDF
@@ -29,26 +29,26 @@ text=نص
font=الخط
selectFillter=- حدد -
pageNum=رقم الصفحة
sizes.small=Small
sizes.medium=Medium
sizes.large=Large
sizes.x-large=X-Large
sizes.small=صغير
sizes.medium=وسط
sizes.large=كبير
sizes.x-large=كبير جدا
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
delete=Delete
username=Username
password=Password
welcome=Welcome
delete=حذف
username=اسم المستخدم
password=كلمة المرور
welcome=مرحبا
property=Property
black=Black
white=White
red=Red
green=Green
blue=Blue
black=أسود
white=أبيض
red=أحمر
green=أخضر
blue=أزرق
custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by
yes=Yes
no=No
yes=نعم
no=لا
changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found.
@@ -62,15 +62,15 @@ downgradeCurrentUserMessage=لا يمكن خفض دور المستخدم الح
downgradeCurrentUserLongMessage=لا يمكن تخفيض دور المستخدم الحالي. وبالتالي، لن يظهر المستخدم الحالي.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error
error=خطأ
oops=Oops!
help=Help
goHomepage=Go to Homepage
help=مساعدة
goHomepage=الى الصفحة الرئيسية
joinDiscord=Join our Discord server
seeDockerHub=See Docker Hub
visitGithub=Visit Github Repository
donate=Donate
color=Color
color=لون
sponsor=Sponsor
info=Info
@@ -109,15 +109,15 @@ pipelineOptions.validateButton=Validate
#############
navbar.favorite=Favorites
navbar.darkmode=الوضع الداكن
navbar.language=Languages
navbar.language=اللغات
navbar.settings=إعدادات
navbar.allTools=Tools
navbar.allTools=أدوات
navbar.multiTool=Multi Tools
navbar.sections.organize=Organize
navbar.sections.convertTo=Convert to PDF
navbar.sections.convertTo=تحويل الى PDF
navbar.sections.convertFrom=Convert from PDF
navbar.sections.security=Sign & Security
navbar.sections.advance=Advanced
navbar.sections.advance=متقدم
navbar.sections.edit=View & Edit
#############
@@ -133,7 +133,7 @@ settings.downloadOption.2=فتح في نافذة جديدة
settings.downloadOption.3=تنزيل الملف
settings.zipThreshold=ملفات مضغوطة عند تجاوز عدد الملفات التي تم تنزيلها
settings.signOut=Sign Out
settings.accountSettings=Account Settings
settings.accountSettings=اعدادات الحساب
settings.bored.help=Enables easter egg game
settings.cacheInputs.name=Save form inputs
settings.cacheInputs.help=Enable to store previously used inputs for future runs
@@ -141,10 +141,10 @@ 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.newUsername=New Username
changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password
changeCreds.confirmNewPassword=Confirm New Password
changeCreds.newUsername=مستخدم جديد
changeCreds.oldPassword=كلمة المرور الحالية
changeCreds.newPassword=كلمة المرور الجديدة
changeCreds.confirmNewPassword=تأكيد كلمة المرور الجديدة
changeCreds.submit=Submit Changes
@@ -191,6 +191,23 @@ adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=تغيير دور المستخدم
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -495,9 +512,9 @@ pdfToSinglePage.submit=Convert To Single Page
#pageExtracter
pageExtracter.title=Extract Pages
pageExtracter.header=Extract Pages
pageExtracter.submit=Extract
pageExtracter.title=استخراج الصفحات
pageExtracter.header=استخراج الصفحات
pageExtracter.submit=استخراج
pageExtracter.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
@@ -505,7 +522,7 @@ pageExtracter.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
getPdfInfo.title=Get Info on PDF
getPdfInfo.header=Get Info on PDF
getPdfInfo.submit=Get Info
getPdfInfo.downloadJson=Download JSON
getPdfInfo.downloadJson=تحميل JSON
#markdown-to-pdf
@@ -683,12 +700,14 @@ removeBlanks.submit=إزالة الفراغات
#removeAnnotations
removeAnnotations.title=Remove Annotations
removeAnnotations.header=Remove Annotations
removeAnnotations.submit=Remove
removeAnnotations.submit=إزالة
#compare
compare.title=يقارن
compare.header=قارن ملفات PDF
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=المستند 1
compare.document.2=المستند 2
compare.submit=يقارن
@@ -801,8 +820,8 @@ addImage.submit=إضافة صورة
#merge
merge.title=دمج
merge.header=دمج ملفات PDF متعددة (2+)
merge.sortByName=Sort by name
merge.sortByDate=Sort by date
merge.sortByName=الترتيب حسب الإسم
merge.sortByDate=الترتيب حسب التاريخ
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=دمج
@@ -821,13 +840,14 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool
multiTool.title=أداة متعددة PDF
multiTool.header=أداة متعددة PDF
multiTool.uploadPrompts=File Name
multiTool.uploadPrompts=إسم الملف
#view pdf
viewPdf.title=View PDF
@@ -868,7 +888,7 @@ imageToPDF.title=صورة إلى PDF
imageToPDF.header=صورة إلى PDF
imageToPDF.submit=تحول
imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page
imageToPDF.fillPage=امل الصفحة
imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=دوران PDF تلقائيًا
@@ -907,7 +927,7 @@ addPassword.selectText.10=منع التعديل
addPassword.selectText.11=منع تعديل التعليقات التوضيحية
addPassword.selectText.12=منع الطباعة
addPassword.selectText.13=منع طباعة تنسيقات مختلفة
addPassword.selectText.14=Owner Password
addPassword.selectText.14=كلمة مرور المالك
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=تشفير
@@ -926,8 +946,8 @@ watermark.selectText.7=التعتيم (0٪ - 100٪):
watermark.selectText.8=Watermark Type:
watermark.selectText.9=Watermark Image:
watermark.submit=إضافة علامة مائية
watermark.type.1=Text
watermark.type.2=Image
watermark.type.1=نص
watermark.type.2=صورة
#Change permissions
@@ -1022,10 +1042,10 @@ PDFToXML.credit=تستخدم هذه الخدمة LibreOffice لتحويل الم
PDFToXML.submit=تحويل
#PDFToCSV
PDFToCSV.title=PDF ??? CSV
PDFToCSV.header=PDF ??? CSV
PDFToCSV.title=PDF الى CSV
PDFToCSV.header=PDF الى CSV
PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=??????
PDFToCSV.submit=تحويل
#split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
@@ -1067,11 +1087,11 @@ split-by-sections.merge=Merge Into One PDF
#printFile
printFile.title=Print File
printFile.header=Print File to Printer
printFile.selectText.1=Select File to Print
printFile.selectText.2=Enter Printer Name
printFile.submit=Print
printFile.title=طباعة ملف
printFile.header=طباعة ملف بالطابعة
printFile.selectText.1=تحديد ملف للطباعة
printFile.selectText.2=ادخل اسم الطابعة
printFile.submit=طباعة
#licenses
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=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
#error
error.sorry=Sorry for the issue!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Съхранете потребителя
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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Премахване
#compare
compare.title=Сравнявай
compare.header=Сравнявай PDF-и
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Документ 1
compare.document.2=Документ 2
compare.submit=Сравнявай
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Четно-нечетно разделяне
pdfOrganiser.mode.7=Премахни първо
pdfOrganiser.mode.8=Премахване на последния
pdfOrganiser.mode.9=Премахване на първия и последния
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(напр. 1,3,2 или 4-8,2,10-12 или 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Модул
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
#error
error.sorry=Извинете за проблема!
@@ -1095,4 +1124,3 @@ error.showStack=Покажи проследяване на стека
error.copyStack=Копиране на проследяване на стека
error.githubSubmit=GitHub - Изпратете запитване
error.discordSubmit=Discord - Изпратете запитване за поддръжка

View File

@@ -191,6 +191,23 @@ adminUserSettings.submit=Desar Usuari
adminUserSettings.changeUserRole=Canvia el rol de l'usuari
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Remove
#compare
compare.title=Comparar
compare.header=Compara PDF
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Comparar
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=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
#error
error.sorry=Sorry for the issue!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Uložit Uživatele
adminUserSettings.changeUserRole=Zmenit Roli Uživatele
adminUserSettings.authenticated=Ověřeno
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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Odebrat
#compare
compare.title=Porovnat
compare.header=Porovnat PDF
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Porovnat
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Liché-Sudé rozdělení
pdfOrganiser.mode.7=Odstranit první
pdfOrganiser.mode.8=Odstranit poslední
pdfOrganiser.mode.9=Odstranit první a poslední
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(např. 1,3,2 nebo 4-8,2,10-12 nebo 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Modul
licenses.version=Verze
licenses.license=Licence
#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
#error
error.sorry=Omlouváme se za potíže!
@@ -1095,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

@@ -86,7 +86,7 @@ pipeline.defaultOption=Benutzerdefiniert
pipeline.submitButton=Speichern
pipeline.help=Hilfe für Pipeline
pipeline.scanHelp=Hilfe zum Ordnerscan
pipeline.deletePrompt=Are you sure you want to delete pipeline
pipeline.deletePrompt=Möchten Sie die Pipeline wirklich löschen?
######################
# Pipeline Options #
@@ -191,6 +191,23 @@ adminUserSettings.submit=Benutzer speichern
adminUserSettings.changeUserRole=Benutzerrolle ändern
adminUserSettings.authenticated=Authentifiziert
database.title=Datenbank Import/Export
database.header=Datenbank Import/Export
database.fileName=Dateiname
database.creationDate=Erstellungsdatum
database.fileSize=Dateigröße
database.deleteBackupFile=Sicherungsdatei löschen
database.importBackupFile=Sicherungsdatei importieren
database.downloadBackupFile=Sicherungsdatei herunterladen
database.info_1=Beim Importieren der Daten ist es von größter Bedeutung, die korrekte Struktur zu gewährleisten. Wenn Sie nicht sicher sind, was Sie tun, suchen Sie Rat und Unterstützung von einem Fachmann. Ein Fehler in der Struktur kann zu Fehlfunktionen der Anwendung führen, bis hin zur vollständigen Nicht-Lauffähigkeit der Anwendung.
database.info_2=Der Dateiname spielt beim Hochladen keine Rolle. Dieser wird nachträglich in das Format backup_user_yyyyMMddHHmm.sql geändert, um eine einheitliche Benennung zu gewährleisten.
database.submit=Sicherungsdatei importieren
database.importIntoDatabaseSuccessed=Import in die Datenbank erfolgreich
database.fileNotFound=Datei nicht gefunden
database.fileNullOrEmpty=Datei darf nicht null oder leer sein
database.failedImportFile=Dateiimport fehlgeschlagen
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Entfernen
#compare
compare.title=Vergleichen
compare.header=PDFs vergleichen
compare.highlightColor.1=Highlight-Farbe 1:
compare.highlightColor.2=Highlight-Farbe 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Vergleichen
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Ungerade-Gerade-Teilung
pdfOrganiser.mode.7=Erste entfernen
pdfOrganiser.mode.8=Letzte entfernen
pdfOrganiser.mode.9=Erste und letzte entfernen
pdfOrganiser.mode.10=Ungerade-Gerade-Zusammenführung
pdfOrganiser.placeholder=(z.B. 1,3,2 oder 4-8,2,10-12 oder 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Modul
licenses.version=Version
licenses.license=Lizenz
#survey
survey.nav=Umfrage
survey.title=Stirling-PDF-Umfrage
survey.description=Stirling-PDF hat kein Tracking, daher möchten wir von unseren Benutzern hören, wie wir Stirling-PDF verbessern können!
survey.please=Bitte nehmen Sie an unserer Umfrage teil!
survey.disabled=(Das Umfrage-Popup wird in folgenden Updates deaktiviert, ist aber am Fuß der Seite verfügbar.)
survey.button=Umfrage durchführen
survey.dontShowAgain=Nicht mehr anzeigen
#error
error.sorry=Entschuldigung für das Problem!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Αποθήκευση Χρήστη
adminUserSettings.changeUserRole=Αλλαγή ρόλου χρήστη
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Κατάργηση
#compare
compare.title=Σύγκριση
compare.header=Σύγκριση PDFs
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Έγγραφο 1
compare.document.2=Έγγραφο 2
compare.submit=Σύγκριση
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Διαίρεση Μονού-Ζυγού
pdfOrganiser.mode.7=Αφαίρεση Πρώτου
pdfOrganiser.mode.8=Αφαίρεση Τελευταίου
pdfOrganiser.mode.9=Αφαίρεση Πρώτου και Τελευταίου
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(π.χ. 1,3,2 ή 4-8,2,10-12 ή 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
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
#error
error.sorry=Συγγνώμη για το ζήτημα!
@@ -1095,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
@@ -191,6 +191,23 @@ adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Change User's Role
adminUserSettings.authenticated=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 to import file
#############
# HOME-PAGE #
#############
@@ -689,6 +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.document.1=Document 1
compare.document.2=Document 2
compare.submit=Compare
@@ -725,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
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1075,12 +1095,21 @@ printFile.submit=Print
#licenses
licenses.nav=Licenses
licenses.title=3rd Party Licenses
licenses.header=3rd Party Licenses
licenses.nav=Licences
licenses.title=3rd Party Licences
licenses.header=3rd Party Licences
licenses.module=Module
licenses.version=Version
licenses.license=License
licenses.license=Licence
#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
#error
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Change User's Role
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +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.document.1=Document 1
compare.document.2=Document 2
compare.submit=Compare
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=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
#error
error.sorry=Sorry for the issue!
@@ -1095,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,7 +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=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 #
@@ -336,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
@@ -459,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
@@ -664,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
@@ -689,6 +706,8 @@ removeAnnotations.submit=Eliminar
#compare
compare.title=Comparar
compare.header=Comparar archivos PDF
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
@@ -725,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
@@ -773,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
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=División par-impar
pdfOrganiser.mode.7=Quitar primera
pdfOrganiser.mode.8=Quitar última
pdfOrganiser.mode.9=Quitar primera y última
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(por ej., 1,3,2 o 4-8,2,10-12 o 2n-1)
@@ -980,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
@@ -1082,6 +1102,15 @@ licenses.module=Módulo
licenses.version=Versión
licenses.license=Licencia
#survey
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
error.sorry=¡Perdón por el fallo!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Gorde Erabiltzailea
adminUserSettings.changeUserRole=Erabiltzailearen rola aldatu
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Remove
#compare
compare.title=Konparatu
compare.header=Konparatu PDF fitxategiak
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=1. dokumentua
compare.document.2=2. dokumentua
compare.submit=Konparatu
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=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
#error
error.sorry=Sorry for the issue!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Ajouter
adminUserSettings.changeUserRole=Changer le rôle de l'utilisateur
adminUserSettings.authenticated=Authentifié
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
#############
# HOME-PAGE #
#############
@@ -271,7 +288,7 @@ home.fileToPDF.desc=Convertissez presque nimporte quel fichiers en PDF (DOCX,
fileToPDF.tags=convertion,transformation,format,document,image,slide,texte,conversion,office,docs,word,excel,powerpoint
home.ocr.title=OCR / Nettoyage des numérisations
home.ocr.desc=Utilisez lOCR pour analyser et détecter le texte des images dun PDF et le rajouter en temps que tel.
home.ocr.desc=Utilisez lOCR pour analyser et détecter le texte des images dun PDF et le rajouter en tant que tel.
ocr.tags=ocr,reconnaissance,texte,image,numérisation,scan,read,identify,detection,editable
@@ -689,6 +706,8 @@ removeAnnotations.submit=Supprimer
#compare
compare.title=Comparer
compare.header=Comparer
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Comparer
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Partage impair-pair
pdfOrganiser.mode.7=Supprimer le premier
pdfOrganiser.mode.8=Supprimer le dernier
pdfOrganiser.mode.9=Supprimer le premier et le dernier
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=Licence
#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
#error
error.sorry=Désolé pour ce problème !
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=उपयोगकर्ता को सहेजे
adminUserSettings.changeUserRole=यूज़र की भूमिका बदलें
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=हटाएं
#compare
compare.title=तुलना करें
compare.header=पीडीएफ़ तुलना करें
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=दस्तावेज़ 1
compare.document.2=दस्तावेज़ 2
compare.submit=तुलना करें
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=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
#error
error.sorry=Sorry for the issue!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Spremi korisnika
adminUserSettings.changeUserRole=Promijenite korisničku ulogu
adminUserSettings.authenticated=Autentificirano
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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Ukloni
#compare
compare.title=Uporedite
compare.header=Usporedite PDF-ove
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokument 1
compare.document.2=Dokument 2
compare.submit=Uporedi
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Par-Nepar Podjela
pdfOrganiser.mode.7=Ukloni Prvu
pdfOrganiser.mode.8=Ukloni Zadnju
pdfOrganiser.mode.9=Ukloni Prvu i Zadnju
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(npr. 1,3,2 ili 4-8,2,10-12 ili 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Modul
licenses.version=Verzija
licenses.license=Licenca
#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
#error
error.sorry=Oprostite zbog problema!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Felhasználó mentése
adminUserSettings.changeUserRole=Felhasználó szerepkörének módosítása
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Remove
#compare
compare.title=Összehasonlítás
compare.header=PDF-ek összehasonlítása
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokumentum 1
compare.document.2=Dokumentum 2
compare.submit=Összehasonlítás
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=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
#error
error.sorry=Sorry for the issue!
@@ -1095,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

@@ -191,6 +191,23 @@ adminUserSettings.submit=Simpan Pengguna
adminUserSettings.changeUserRole=Ubah Peran Pengguna
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=Hapus
#compare
compare.title=Bandingkan
compare.header=Bandingkan PDF
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Dokumen 1
compare.document.2=Dokumen 2
compare.submit=Bandingkan
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Module
licenses.version=Version
licenses.license=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
#error
error.sorry=Sorry for the issue!
@@ -1095,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

@@ -35,7 +35,7 @@ sizes.large=Largo
sizes.x-large=Extra-Large
error.pdfPassword=Il documento PDF è protetto da password e la password non è stata fornita oppure non era corretta
delete=Elimina
username=Username
username=Nome utente
password=Password
welcome=Benvenuto
property=Proprietà
@@ -86,7 +86,7 @@ pipeline.defaultOption=Personalizzato
pipeline.submitButton=Invia
pipeline.help=Aiuto sulla pipeline
pipeline.scanHelp=Aiuto per la scansione delle cartelle
pipeline.deletePrompt=Are you sure you want to delete pipeline
pipeline.deletePrompt=Sei sicuro di voler eliminare la pipeline?
######################
# Pipeline Options #
@@ -116,7 +116,7 @@ navbar.multiTool=Strumenti multipli
navbar.sections.organize=Organizza
navbar.sections.convertTo=Converti in PDF
navbar.sections.convertFrom=Converti da PDF
navbar.sections.security=Firma Firma & Sicurezza
navbar.sections.security=Firma & Sicurezza
navbar.sections.advance=Avanzate
navbar.sections.edit=Visualizza & Modifica
@@ -191,6 +191,23 @@ adminUserSettings.submit=Salva utente
adminUserSettings.changeUserRole=Cambia il ruolo dell'utente
adminUserSettings.authenticated=Autenticato
database.title=Importazione/Esportazione database
database.header=Importazione/esportazione database
database.fileName=Nome file
database.creationDate=Data di creazione
database.fileSize=Dimensione
database.deleteBackupFile=Elimina file di backup
database.importBackupFile=Importa file di backup
database.downloadBackupFile=Scarica il file di backup
database.info_1=Quando si importano i dati, è fondamentale garantire la struttura corretta. Se non sei sicuro di quello che stai facendo, chiedi consiglio e supporto a un professionista. Un errore nella struttura può causare malfunzionamenti dell'applicazione, fino alla completa impossibilità di eseguire l'applicazione.
database.info_2=Il nome del file non ha importanza durante il caricamento. Verrà rinominato in seguito per seguire il formato backup_user__yyyyMMddHHmm.sql,garantendo una convenzione di denominazione coerente.
database.submit=Importa Backup
database.importIntoDatabaseSuccessed=L'importazione nel database è avvenuta con successo
database.fileNotFound=File non trovato
database.fileNullOrEmpty=Il file non deve essere nullo o vuoto
database.failedImportFile=Importazione file non riuscita
#############
# HOME-PAGE #
#############
@@ -234,7 +251,7 @@ pdfOrganiser.tags=duplex,pari,dispari,ordinamento,spostamento
home.addImage.title=Aggiungi Immagine
home.addImage.desc=Aggiungi un'immagine in un punto specifico del PDF (Lavori in corso)
addImage.tags=img,jpg,immagine,photo
addImage.tags=img,jpg,immagine,foto
home.watermark.title=Aggiungi Filigrana
home.watermark.desc=Aggiungi una filigrana al tuo PDF.
@@ -689,6 +706,8 @@ removeAnnotations.submit=Rimuovi
#compare
compare.title=Compara
compare.header=Compara PDF
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
@@ -803,7 +822,7 @@ merge.title=Unisci
merge.header=Unisci 2 o più PDF
merge.sortByName=Ordina per nome
merge.sortByDate=Ordina per data
merge.removeCertSign=Remove digital signature in the merged file?
merge.removeCertSign=Rimuovere la firma digitale nel file unito?
merge.submit=Unisci
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=Divisione pari-dispari
pdfOrganiser.mode.7=Rimuovi prima
pdfOrganiser.mode.8=Rimuovi ultima
pdfOrganiser.mode.9=Rimuovi la prima e l'ultima
pdfOrganiser.mode.10=Unione pari-dispari
pdfOrganiser.placeholder=(ad es. 1,3,2 o 4-8,2,10-12 o 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=Modulo
licenses.version=Versione
licenses.license=Licenza
#survey
survey.nav=Sondaggio
survey.title=Sondaggio Stirling-PDF
survey.description=Stirling-PDF non fa tracciamento, quindi vogliamo sentire i nostri utenti per migliorare Stirling-PDF!
survey.please=Ti invitiamo a prendere in considerazione la possibilità di partecipare al nostro sondaggio!
survey.disabled=(Il popup del sondaggio verrà disabilitato nei prossimi aggiornamenti ma sarà disponibile a piè di pagina)
survey.button=Partecipa al sondaggio
survey.dontShowAgain=Non mostrare più
#error
error.sorry=Ci scusiamo per il problema!
@@ -1095,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

@@ -55,13 +55,13 @@ userNotFoundMessage=ユーザーが見つかりません。
incorrectPasswordMessage=現在のパスワードが正しくありません。
usernameExistsMessage=新しいユーザー名はすでに存在します。
invalidUsernameMessage=ユーザー名が無効です。ユーザー名には文字、数字、およびそれに続く特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
confirmPasswordErrorMessage=新しいパスワードと新しいパスワードの確認は一致する必要があります。
deleteCurrentUserMessage=現在ログインしているユーザーは削除できません。
deleteUsernameExistsMessage=そのユーザー名は存在しないため削除できません。
downgradeCurrentUserMessage=現在のユーザーの役割をダウングレードできません
downgradeCurrentUserLongMessage=現在のユーザーの役割をダウングレードできません。したがって、現在のユーザーは表示されません。
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
userAlreadyExistsOAuthMessage=ユーザーは既にOAuth2ユーザーとして存在します。
userAlreadyExistsWebMessage=ユーザーは既にWebユーザーとして存在します。
error=エラー
oops=おっと!
help=ヘルプ
@@ -86,7 +86,7 @@ pipeline.defaultOption=カスタム
pipeline.submitButton=送信
pipeline.help=パイプラインのヘルプ
pipeline.scanHelp=フォルダ スキャンのヘルプ
pipeline.deletePrompt=Are you sure you want to delete pipeline
pipeline.deletePrompt=パイプラインを削除してもよろしいですか
######################
# Pipeline Options #
@@ -109,23 +109,23 @@ pipelineOptions.validateButton=検証
#############
navbar.favorite=Favorites
navbar.darkmode=ダークモード
navbar.language=Languages
navbar.language=言語
navbar.settings=設定
navbar.allTools=Tools
navbar.multiTool=Multi Tools
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.allTools=ツール
navbar.multiTool=マルチツール
navbar.sections.organize=整理
navbar.sections.convertTo=PDFへ変換
navbar.sections.convertFrom=PDFから変換
navbar.sections.security=署名とセキュリティ
navbar.sections.advance=アドバンスド
navbar.sections.edit=閲覧と編集
#############
# SETTINGS #
#############
settings.title=設定
settings.update=利用可能なアップデート
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
settings.updateAvailable=バージョン {0} がインストールされています。 新しいバージョン ({1}) が利用可能です。
settings.appVersion=Appバージョン:
settings.downloadOption.title=ダウンロードオプション (zip以外の単一ファイル):
settings.downloadOption.1=同じウィンドウで開く
@@ -134,9 +134,9 @@ settings.downloadOption.3=ファイルをダウンロード
settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する
settings.signOut=サインアウト
settings.accountSettings=アカウント設定
settings.bored.help=Enables easter egg game
settings.cacheInputs.name=Save form inputs
settings.cacheInputs.help=Enable to store previously used inputs for future runs
settings.bored.help=イースターエッグゲームを有効にする
settings.cacheInputs.name=フォームの入力を保存する
settings.cacheInputs.help=以前使用した入力を保存し、次回から使用できるようにする。
changeCreds.title=資格情報の変更
changeCreds.header=アカウントの詳細を更新する
@@ -175,8 +175,8 @@ adminUserSettings.header=管理者ユーザー制御設定
adminUserSettings.admin=管理者
adminUserSettings.user=ユーザー
adminUserSettings.addUser=新しいユーザを追加
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.deleteUser=ユーザの削除
adminUserSettings.confirmDeleteUser=ユーザを本当に削除しますか?
adminUserSettings.usernameInfo=ユーザー名には、文字、数字、および次の特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります。
adminUserSettings.roles=役割
adminUserSettings.role=役割
@@ -189,7 +189,24 @@ adminUserSettings.internalApiUser=内部APIユーザー
adminUserSettings.forceChange=ログイン時にユーザー名/パスワードを強制的に変更する
adminUserSettings.submit=ユーザーの保存
adminUserSettings.changeUserRole=ユーザーの役割を変更する
adminUserSettings.authenticated=Authenticated
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
#############
# HOME-PAGE #
@@ -336,8 +353,8 @@ home.certSign.title=証明書による署名
home.certSign.desc=証明書/キーを使用してPDFに署名します。 (PEM/P12)
certSign.tags=authenticate,PEM,P12,official,encrypt
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
home.removeCertSign.title=証明書の署名を削除する
home.removeCertSign.desc=PDFから証明書署名を削除する
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=マルチページレイアウト
@@ -460,12 +477,12 @@ login.locked=あなたのアカウントはロックされています。
login.signinTitle=サインインしてください
login.ssoSignIn=シングルサインオンでログイン
login.oauth2AutoCreateDisabled=OAuth 2自動作成ユーザーが無効
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=認証リクエストが見つかりません
login.oauth2InvalidUserInfoResponse=無効なユーザー情報の応答
login.oauth2invalidRequest=無効なリクエスト
login.oauth2AccessDenied=アクセス拒否
login.oauth2InvalidTokenResponse=無効なトークン応答
login.oauth2InvalidIdToken=無効なIDトークン
#auto-redact
@@ -664,10 +681,10 @@ certSign.submit=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=証明書署名の削除
removeCertSign.header=PDFから電子証明書を削除する
removeCertSign.selectPDF=PDFファイルの選択:
removeCertSign.submit=署名の削除
#removeBlanks
@@ -689,6 +706,8 @@ removeAnnotations.submit=削除
#compare
compare.title=比較
compare.header=PDFの比較
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=ドキュメント 1
compare.document.2=ドキュメント 2
compare.submit=比較
@@ -725,7 +744,7 @@ repair.submit=修復
#flatten
flatten.title=平坦化
flatten.header=PDFを平坦化する
flatten.flattenOnlyForms=Flatten only forms
flatten.flattenOnlyForms=フォームのみを平坦にする
flatten.submit=平坦化
@@ -752,7 +771,7 @@ ocr.selectText.4=ページをきれいにして背景ノイズの中からテキ
ocr.selectText.5=ページをきれいにして背景ノイズの中からテキストを検出しにくくし、出力はクリーンアップを維持する。
ocr.selectText.6=インタラクティブなテキストを含むページを無視し、画像ページのみをOCRする
ocr.selectText.7=強制OCR、全てのページで元のテキスト要素を全て削除してOCRする
ocr.selectText.8=Normal (PDFにテキストが含まれている場合はエラーになります。)
ocr.selectText.8=ノーマル (PDFにテキストが含まれている場合はエラーになります。)
ocr.selectText.9=追加設定
ocr.selectText.10=OCRモード
ocr.selectText.11=OCR後に画像を削除する (すべての画像を削除します。変換ステップの一部である場合にのみ有効です)。
@@ -773,7 +792,7 @@ extractImages.submit=抽出
fileToPDF.title=ファイルをPDFに変換
fileToPDF.header=あらゆるファイルをPDFに変換
fileToPDF.credit=本サービスはファイル変換にLibreOfficeとUnoconvを使用しています。
fileToPDF.supportedFileTypesInfo=Supported File types
fileToPDF.supportedFileTypesInfo=サポートされるファイル形式
fileToPDF.supportedFileTypes=サポートされるファイル形式には以下が含まれますが、完全な更新リストについてはLibreOfficeのドキュメントを参照してください。
fileToPDF.submit=PDFを変換
@@ -803,7 +822,7 @@ merge.title=結合
merge.header=複数のPDFを結合 (2ファイル以上)
merge.sortByName=名前で並べ替え
merge.sortByDate=日付で並べ替え
merge.removeCertSign=Remove digital signature in the merged file?
merge.removeCertSign=結合されたファイル内のデジタル署名を削除しますか?
merge.submit=結合
@@ -821,13 +840,14 @@ pdfOrganiser.mode.6=奇数-偶数分割
pdfOrganiser.mode.7=最初に削除
pdfOrganiser.mode.8=最後を削除
pdfOrganiser.mode.9=最初と最後を削除
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1)
#multiTool
multiTool.title=PDFマルチツール
multiTool.header=PDFマルチツール
multiTool.uploadPrompts=File Name
multiTool.uploadPrompts=ファイル名
#view pdf
viewPdf.title=PDFを表示
@@ -981,7 +1001,7 @@ pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用してい
pdfToPDFA.submit=変換
pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません
pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
pdfToPDFA.pdfWithDigitalSignature=PDF にはデジタル署名が含まれています。これは次の手順で削除されます。
#PDFToWord
@@ -1067,11 +1087,11 @@ split-by-sections.merge=1 つの PDF に結合するかどうか
#printFile
printFile.title=Print File
printFile.header=Print File to Printer
printFile.selectText.1=Select File to Print
printFile.selectText.2=Enter Printer Name
printFile.submit=Print
printFile.title=ファイルの印刷
printFile.header=ファイルをプリンタで印刷
printFile.selectText.1=印刷するファイルを選択
printFile.selectText.2=プリンタ名を入力
printFile.submit=プリント
#licenses
@@ -1082,6 +1102,15 @@ licenses.module=モジュール
licenses.version=バージョン
licenses.license=ライセンス
#survey
survey.nav=アンケート
survey.title=Stirling-PDFのアンケート
survey.description=Stirling-PDFには追跡機能がないため、Stirling-PDFをより良くするために皆様の意見を聞かせてください
survey.please=アンケートにご協力ください!
survey.disabled=(アンケートのポップアップは、次の更新では無効になりますが、ページの下部に表示されます。)
survey.button=アンケートに答える
survey.dontShowAgain=再び表示しない
#error
error.sorry=問題が発生したことをお詫び申し上げます!
@@ -1095,4 +1124,3 @@ error.showStack=スタックトレースを表示
error.copyStack=スタックトレースをコピー
error.githubSubmit=GitHub - チケットを提出
error.discordSubmit=Discord - サポート投稿を提出

View File

@@ -191,6 +191,23 @@ adminUserSettings.submit=사용자 저장
adminUserSettings.changeUserRole=사용자의 역할 변경
adminUserSettings.authenticated=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
#############
# HOME-PAGE #
#############
@@ -689,6 +706,8 @@ removeAnnotations.submit=제거하다
#compare
compare.title=비교
compare.header=PDF 문서 비교
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=문서 1
compare.document.2=문서 2
compare.submit=비교
@@ -821,6 +840,7 @@ pdfOrganiser.mode.6=홀수-짝수 분할
pdfOrganiser.mode.7=첫 번째 항목 삭제
pdfOrganiser.mode.8=마지막 항목 제거
pdfOrganiser.mode.9=첫 번째와 마지막 제거
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(예: 1,3,2 또는 4-8,2,10-12 또는 2n-1)
@@ -1082,6 +1102,15 @@ licenses.module=모듈
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
#error
error.sorry=문제를 끼친 점 죄송합니다!
@@ -1095,4 +1124,3 @@ error.showStack=스택 추적 보기
error.copyStack=스택 추적 복사
error.githubSubmit=GitHub - 티켓 제출
error.discordSubmit=Discord - 문의 게시

View File

@@ -11,17 +11,17 @@ imgPrompt=Selecteer afbeelding(en)
genericSubmit=Indienen
processTimeWarning=Waarschuwing: Dit proces kan tot een minuut duren afhankelijk van de bestandsgrootte
pageOrderPrompt=Aangepaste pagina volgorde (Voer een komma-gescheiden lijst van paginanummers of functies in, zoals 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
pageSelectionPrompt=Aangepaste pagina selectie (Voer een komma-gescheiden lijst van paginanummer 1,5,6 of functies zoals 2n+1 in) :
goToPage=Ga
true=Waar
false=Onwaar
unknown=Onbekend
save=Opslaan
saveToBrowser=Save to Browser
saveToBrowser=Opslaan in browser
close=Sluiten
filesSelected=Bestanden geselecteerd
noFavourites=Geen favorieten toegevoegd
downloadComplete=Download Complete
downloadComplete=Download klaar
bored=Verveeld met wachten?
alphabet=Alfabet
downloadPdf=Download PDF
@@ -54,23 +54,23 @@ notAuthenticatedMessage=Gebruiker niet ingelogd.
userNotFoundMessage=Gebruiker niet gevonden.
incorrectPasswordMessage=Huidige wachtwoord is onjuist.
usernameExistsMessage=Nieuwe gebruikersnaam bestaat al.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
invalidUsernameMessage=Ongeldige gebruikersnaam, gebruikersnaam kan alleen letters, nummers en de volgende speciale tekens @._+- bevatten of moet een geldig emailadres zijn.
confirmPasswordErrorMessage=Nieuw wachtwoord en bevestig wachtwoord moeten overeenkomen.
deleteCurrentUserMessage=Kan niet een momenteel ingelogde gebruiker verwijderen.
deleteUsernameExistsMessage=De gebruikersnaam bestaat niet en kan niet verwijderd worden.
downgradeCurrentUserMessage=Kan de rol van de huidige gebruiker niet downgraden
downgradeCurrentUserLongMessage=Kan de rol van de huidige gebruiker niet downgraden. Huidige gebruiker wordt dus niet weergegeven.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
userAlreadyExistsOAuthMessage=De gebruiker bestaat al als een OAuth2 gebruiker.
userAlreadyExistsWebMessage=De gebruiker bestaat al als een web gebruiker.
error=Error
oops=Oops!
oops=Oeps!
help=Help
goHomepage=Go to Homepage
joinDiscord=Join our Discord server
seeDockerHub=See Docker Hub
visitGithub=Visit Github Repository
donate=Donate
color=Color
goHomepage=Ga naar de startpagina
joinDiscord=Word lid van onze Discord server
seeDockerHub=Zie Docker Hub
visitGithub=Ga naar de Github Repository
donate=Doneer
color=Kleur
sponsor=Sponsor
info=Info
@@ -79,14 +79,14 @@ info=Info
###############
# Pipeline #
###############
pipeline.header=Pijplijn menu (Alpha)
pipeline.header=Pijplijn menu (Beta)
pipeline.uploadButton=Aangepast uploaden
pipeline.configureButton=Configureren
pipeline.defaultOption=Aangepast
pipeline.submitButton=Opslaan
pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
pipeline.help=Pijplijn help
pipeline.scanHelp=Map scannen help
pipeline.deletePrompt=Weet je zeker dat je deze pijplijn wil verwijderen?
######################
# Pipeline Options #
@@ -107,25 +107,25 @@ pipelineOptions.validateButton=Valideren
#############
# NAVBAR #
#############
navbar.favorite=Favorites
navbar.favorite=Favorieten
navbar.darkmode=Donkere modus
navbar.language=Languages
navbar.language=Talen
navbar.settings=Instellingen
navbar.allTools=Tools
navbar.multiTool=Multi Tools
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.multiTool=Multitools
navbar.sections.organize=Organizeren
navbar.sections.convertTo=Converteren naar PDF
navbar.sections.convertFrom=Converteren van PDF
navbar.sections.security=Ondertekenen & beveiliging
navbar.sections.advance=Geavanceerd
navbar.sections.edit=Bekijken & wijzigen
#############
# SETTINGS #
#############
settings.title=Instellingen
settings.update=Update beschikbaar
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
settings.updateAvailable={0} is de huidig geïnstalleerde versie. Een nieuwe versie ({1}) is beschikbaar.
settings.appVersion=App versie:
settings.downloadOption.title=Kies download optie (Voor enkelvoudige bestanddownloads zonder zip):
settings.downloadOption.1=Open in hetzelfde venster
@@ -134,13 +134,13 @@ settings.downloadOption.3=Download bestand
settings.zipThreshold=Bestanden zippen wanneer het aantal gedownloade bestanden meer is dan
settings.signOut=Uitloggen
settings.accountSettings=Account instellingen
settings.bored.help=Enables easter egg game
settings.cacheInputs.name=Save form inputs
settings.cacheInputs.help=Enable to store previously used inputs for future runs
settings.bored.help=Schakelt geheim spelletje in
settings.cacheInputs.name=Sla invoer in formulieren op
settings.cacheInputs.help=Schakel in om eerdere invoeren op te slaan voor toekomstige uitvoeren
changeCreds.title=Inloggegevens wijzigen
changeCreds.header=Werk je accountgegevens bij
changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.changePassword=Je gebruikt de standaard inloggegevens. Voer alstublieft een nieuw wachtwoord in
changeCreds.newUsername=Nieuwe gebruikersnaam
changeCreds.oldPassword=Huidige wachtwoord
changeCreds.newPassword=Nieuw wachtwoord
@@ -175,27 +175,44 @@ adminUserSettings.header=Beheer gebruikers
adminUserSettings.admin=Beheerder
adminUserSettings.user=Gebruiker
adminUserSettings.addUser=Voeg nieuwe gebruiker toe
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.deleteUser=Verwijder gebruiker
adminUserSettings.confirmDeleteUser=Moet deze gebruiker verwijderd worden?
adminUserSettings.usernameInfo=Gebruikersnaam kan alleen letters, nummers en de volgende speciale tekens @._+- bevatten of moet een geldig emailadres zijn.
adminUserSettings.roles=Rollen
adminUserSettings.role=Rol
adminUserSettings.actions=Acties
adminUserSettings.apiUser=Beperkte API gebruiker
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.extraApiUser=Extra beperkte API gebruiker
adminUserSettings.webOnlyUser=Alleen web gebruiker
adminUserSettings.demoUser=Demogebruiker (geen aangepaste instellingen)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.internalApiUser=Interne API gebruiker
adminUserSettings.forceChange=Forceer gebruiker om gebruikersnaam/wachtwoord te wijzigen bij inloggen
adminUserSettings.submit=Gebruiker opslaan
adminUserSettings.changeUserRole=De rol van de gebruiker wijzigen
adminUserSettings.authenticated=Authenticated
adminUserSettings.authenticated=Geauthenticeerd
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
#############
# HOME-PAGE #
#############
home.desc=Jouw lokaal gehoste one-stop-shop voor al je PDF-behoeften.
home.searchBar=Zoeken naar functies...
home.searchBar=Zoek naar functies...
home.viewPdf.title=PDF bekijken
@@ -204,11 +221,11 @@ viewPdf.tags=bekijken,lezen,annoteren,tekst,afbeelding
home.multiTool.title=PDF multitool
home.multiTool.desc=Pagina's samenvoegen, draaien, herschikken en verwijderen
multiTool.tags=Multitool,Multi bewerking,UI,klik sleep,voorkant,clientzijde,interactief,beweegbaar,verplaats
multiTool.tags=Multitool,meerdere bewerkingen,UI,klik sleep,voorkant,clientzijde,interactief,beweegbaar,verplaats
home.merge.title=Samenvoegen
home.merge.desc=Voeg eenvoudig meerdere PDF's samen tot één.
merge.tags=samenvoegen,Pagina bewerkingen,Serverkant
merge.tags=samenvoegen,pagina bewerkingen,serverzijde
home.split.title=Splitsen
home.split.desc=Splits PDF's in meerdere documenten
@@ -255,7 +272,7 @@ addPassword.tags=veilig,beveiliging
home.removePassword.title=Wachtwoord verwijderen
home.removePassword.desc=Verwijder wachtwoordbeveiliging van je PDF-document.
removePassword.tags=veilig,Decrypteren,beveiliging,wachtwoord verwijderen
removePassword.tags=veilig,ontsleutelen,beveiliging,wachtwoord verwijderen
home.compressPdfs.title=Comprimeren
home.compressPdfs.desc=Comprimeer PDF's om hun bestandsgrootte te verkleinen.
@@ -336,9 +353,9 @@ home.certSign.title=Ondertekenen met certificaat
home.certSign.desc=Ondertekent een PDF met een certificaat/sleutel (PEM/P12)
certSign.tags=authenticeren,PEM,P12,officieel,versleutelen
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.removeCertSign.title=Verwijder certificaat
home.removeCertSign.desc=Verwijder certificaat van PDF
removeCertSign.tags=authenticeren,PEM,P12,officieel,ontsleutelen
home.pageLayout.title=Multi-pagina indeling
home.pageLayout.desc=Voeg meerdere pagina's van een PDF-document samen op één pagina
@@ -436,13 +453,13 @@ home.AddStampRequest.desc=Voeg tekst of afbeeldingsstempels toe op vaste locatie
AddStampRequest.tags=Stempel, Afbeelding toevoegen, afbeelding centreren, watermerk, PDF, Insluiten, Aanpassen
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.PDFToBook.title=PDF naar Boek
home.PDFToBook.desc=Converteert PDF naar boek-/stripformaat met gebruik van Calibre
PDFToBook.tags=Boek,Strip,Comic,Calibre,Converteren,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Boek naar PDF
home.BookToPDF.desc=Converteert boek-/stripformaat naar PDF met gebruik van Calibre
BookToPDF.tags=Boek,Strip,Comic,Calibre,Converteren,manga,amazon,kindle
###########################
@@ -460,12 +477,12 @@ login.locked=Je account is geblokkeerd.
login.signinTitle=Gelieve in te loggen
login.ssoSignIn=Inloggen via Single Sign-on
login.oauth2AutoCreateDisabled=OAUTH2 Automatisch aanmaken gebruiker uitgeschakeld
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=Autorisatieverzoek niet gevonden
login.oauth2InvalidUserInfoResponse=Ongeldige reactie op gebruikersinfo
login.oauth2invalidRequest=Ongeldig verzoek
login.oauth2AccessDenied=Toegang geweigerd
login.oauth2InvalidTokenResponse=Ongeldige tokenreactie
login.oauth2InvalidIdToken=Ongeldige ID token
#auto-redact
@@ -512,7 +529,7 @@ getPdfInfo.downloadJson=Download JSON
MarkdownToPDF.title=Markdown naar PDF
MarkdownToPDF.header=Markdown naar PDF
MarkdownToPDF.submit=Converteren
MarkdownToPDF.help=in ontwikkeling
MarkdownToPDF.help=In ontwikkeling
MarkdownToPDF.credit=Gebruikt WeasyPrint
@@ -542,7 +559,7 @@ HTMLToPDF.defaultHeader=Standaard koptekst weergeven (naam en paginanummer)
HTMLToPDF.cssMediaType=Wijzig het CSS-mediatype van de pagina.
HTMLToPDF.none=Geen
HTMLToPDF.print=Print
HTMLToPDF.screen=Screen
HTMLToPDF.screen=Scherm
#AddStampRequest
@@ -664,10 +681,10 @@ certSign.submit=PDF ondertekenen
#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=Verwijder certificaat
removeCertSign.header=Verwijder het digitale certificaat van de PDF
removeCertSign.selectPDF=Selecteer een PDF bestand:
removeCertSign.submit=Verwijder certificaat
#removeBlanks
@@ -689,22 +706,24 @@ removeAnnotations.submit=Verwijderen
#compare
compare.title=Vergelijken
compare.header=PDF's vergelijken
compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1
compare.document.2=Document 2
compare.submit=Vergelijken
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
BookToPDF.title=Boeken en strips naar PDF
BookToPDF.header=Boek naar PDF
BookToPDF.credit=Gebruikt Calibre
BookToPDF.submit=Converteer
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
PDFToBook.title=PDF naar boek
PDFToBook.header=PDF naar boek
PDFToBook.selectText.1=Formaat
PDFToBook.credit=Gebruikt Calibre
PDFToBook.submit=Converteer
#sign
sign.title=Ondertekenen
@@ -725,7 +744,7 @@ repair.submit=Repareren
#flatten
flatten.title=Afvlakken
flatten.header=PDF's afvlakken
flatten.flattenOnlyForms=Flatten only forms
flatten.flattenOnlyForms=Alleen formulieren afvlakken
flatten.submit=Afvlakken
@@ -756,7 +775,7 @@ ocr.selectText.8=Normaal (Zal een fout geven als de PDF tekst bevat)
ocr.selectText.9=Aanvullende instellingen
ocr.selectText.10=OCR-modus
ocr.selectText.11=Verwijder afbeeldingen na OCR (Verwijdert ALLE afbeeldingen, alleen nuttig als onderdeel van conversiestap)
ocr.selectText.12=Render Type (Geavanceerd)
ocr.selectText.12=Weergave Type (Geavanceerd)
ocr.help=Lees deze documentatie over hoe dit te gebruiken voor andere talen en/of gebruik buiten docker
ocr.credit=Deze dienst maakt gebruik van OCRmyPDF en Tesseract voor OCR.
ocr.submit=Verwerk PDF met OCR
@@ -803,7 +822,7 @@ merge.title=Samenvoegen
merge.header=Meerdere PDF's samenvoegen (2+)
merge.sortByName=Sorteer op naam
merge.sortByDate=Sorteer op datum
merge.removeCertSign=Remove digital signature in the merged file?
merge.removeCertSign=Verwijder digitale handtekening in het samengevoegde bestand?
merge.submit=Samenvoegen
@@ -811,23 +830,24 @@ merge.submit=Samenvoegen
pdfOrganiser.title=Pagina organisator
pdfOrganiser.header=PDF pagina organisator
pdfOrganiser.submit=Pagina's herschikken
pdfOrganiser.mode=Mode
pdfOrganiser.mode.1=Custom Page Order
pdfOrganiser.mode.2=Reverse Order
pdfOrganiser.mode.3=Duplex Sort
pdfOrganiser.mode.4=Booklet Sort
pdfOrganiser.mode.5=Side Stitch Booklet Sort
pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
pdfOrganiser.mode=Modus
pdfOrganiser.mode.1=Aangepaste paginavolgorde
pdfOrganiser.mode.2=Omgekeerde volgorde
pdfOrganiser.mode.3=Duplex sorteren
pdfOrganiser.mode.4=Boekje sorteren
pdfOrganiser.mode.5=Zijsteek boekje sorteren
pdfOrganiser.mode.6=Oneven-even splitsen
pdfOrganiser.mode.7=Eerste verwijderen
pdfOrganiser.mode.8=Laatste verwijderen
pdfOrganiser.mode.9=Eerste en laaste verwijderen
pdfOrganiser.mode.10=Oneven-even samenvoeken
pdfOrganiser.placeholder=(bijv. 1,3,2 of 4-8,2,10-12 of 2n-1)
#multiTool
multiTool.title=PDF Multitool
multiTool.header=PDF Multitool
multiTool.uploadPrompts=File Name
multiTool.uploadPrompts=Bestandsnaam
#view pdf
viewPdf.title=PDF bekijken
@@ -838,7 +858,7 @@ pageRemover.title=Pagina verwijderaar
pageRemover.header=PDF pagina verwijderaar
pageRemover.pagesToDelete=Te verwijderen pagina's (Voer een door komma's gescheiden lijst met paginanummers in):
pageRemover.submit=Pagina's verwijderen
pageRemover.placeholder=(e.g. 1,2,6 or 1-10,15-30)
pageRemover.placeholder=(bijv. 1,2,6 of 1-10,15-30)
#rotate
@@ -979,9 +999,9 @@ pdfToPDFA.title=PDF naar PDF/A
pdfToPDFA.header=PDF naar PDF/A
pdfToPDFA.credit=Deze service gebruikt OCRmyPDF voor PDF/A-conversie
pdfToPDFA.submit=Converteren
pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.tip=Werkt momenteel niet voor meerdere inputs tegelijkertijd.
pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
pdfToPDFA.pdfWithDigitalSignature=Dit PDF bestand bevat een digitale handtekening. Deze wordt in de volgende stap verwijderd.
#PDFToWord
@@ -1063,14 +1083,14 @@ split-by-sections.vertical.label=Verticale secties
split-by-sections.horizontal.placeholder=Voer het aantal horizontale secties in
split-by-sections.vertical.placeholder=Voer het aantal verticale secties in
split-by-sections.submit=PDF splitsen
split-by-sections.merge=Merge Into One PDF
split-by-sections.merge=Samenvoegen in één PDF
#printFile
printFile.title=Print File
printFile.header=Print File to Printer
printFile.selectText.1=Select File to Print
printFile.selectText.2=Enter Printer Name
printFile.title=Print bestand
printFile.header=Print bestand naar printer
printFile.selectText.1=Selecteer bestand om te printen
printFile.selectText.2=Voer printernaam in
printFile.submit=Print
@@ -1082,17 +1102,25 @@ licenses.module=Module
licenses.version=Versie
licenses.license=Licentie
#survey
survey.nav=Enquête
survey.title=Stirling-PDF Enquête
survey.description=Stirling-PDF heeft geen tracking, dus we willen van onze gebruikers horen om Stirling-PDF te verbeteren.
survey.please=Overweeg alstublieft om onze enquête in te vullen!
survey.disabled=(Enquête popup wordt in een toekomstige update weggehaald, maar is beschikbaar aan de onderkant van de pagina.)
survey.button=Vul enquête in.
survey.dontShowAgain=Niet weer tonen
#error
error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:
error.404.head=404 - Page Not Found | Oops, we tripped in the code!
error.404.1=We can't seem to find the page you're looking for.
error.404.2=Something went wrong
error.github=Submit a ticket on GitHub
error.showStack=Show Stack Trace
error.copyStack=Copy Stack Trace
error.githubSubmit=GitHub - Submit a ticket
error.discordSubmit=Discord - Submit Support post
error.sorry=Excuses voor het probleem!
error.needHelp=Hulp nodig / probleem gevonden?
error.contactTip=Als je nog steeds problemen hebt, schroom niet om contact met ons op te nemen voor hulp. Je kan een ticket op onze Github pagina indienen of ons via Discord bereiken:
error.404.head=404 - Pagina niet gevonden | Oeps, we struikelden over de code!
error.404.1=We kunnen de pagina die je zoek niet vinden.
error.404.2=Er ging iets mis.
error.github=Dien een ticket op Github in.
error.showStack=Geeft tracering weer
error.copyStack=Kopieer tracering
error.githubSubmit=GitHub - Dien een ticket in
error.discordSubmit=Discord - Maak een support post

Some files were not shown because too many files have changed in this diff Show More