Compare commits

...

155 Commits

Author SHA1 Message Date
dependabot[bot]
4c4c22e861 Merge pull request #252 from Frooodle/dependabot/gradle/org.springframework.boot-3.1.1 2023-07-02 17:41:23 +00:00
Anthony Stirling
00e27d9327 Merge branch 'main' into dependabot/gradle/org.springframework.boot-3.1.1 2023-07-02 18:39:22 +01:00
dependabot[bot]
f082278041 Merge pull request #253 from Frooodle/dependabot/gradle/org.springframework.boot-spring-boot-starter-thymeleaf-3.1.1 2023-07-02 17:38:09 +00:00
Anthony Stirling
09dde64c57 Merge branch 'main' into dependabot/gradle/org.springframework.boot-spring-boot-starter-thymeleaf-3.1.1 2023-07-02 18:37:20 +01:00
dependabot[bot]
b52a6357f6 Merge pull request #239 from Frooodle/dependabot/gradle/edu.sc.seis.launch4j-3.0.3 2023-07-02 17:34:15 +00:00
Anthony Stirling
f14a566d06 Merge branch 'main' into dependabot/gradle/edu.sc.seis.launch4j-3.0.3 2023-07-02 18:33:21 +01:00
Anthony Stirling
b352ec6888 Merge pull request #234 from Frooodle/dependabot/gradle/commons-io-commons-io-2.13.0
Bump commons-io:commons-io from 2.11.0 to 2.13.0
2023-07-02 18:33:12 +01:00
Anthony Stirling
4ec1bad03d Merge branch 'main' into dependabot/gradle/commons-io-commons-io-2.13.0 2023-07-02 18:32:22 +01:00
Anthony Stirling
f20bbc119d Merge branch 'main' into dependabot/gradle/org.springframework.boot-spring-boot-starter-thymeleaf-3.1.1 2023-07-02 18:32:14 +01:00
Anthony Stirling
8555c3d422 Merge branch 'main' into dependabot/gradle/org.springframework.boot-3.1.1 2023-07-02 18:32:08 +01:00
Anthony Stirling
71f9d03b19 Merge pull request #251 from albertopasqualetto/main
addImage text was wrong
2023-07-02 18:31:33 +01:00
dependabot[bot]
0b31379078 Bump org.springframework.boot:spring-boot-starter-thymeleaf
Bumps [org.springframework.boot:spring-boot-starter-thymeleaf](https://github.com/spring-projects/spring-boot) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-thymeleaf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-02 17:30:55 +00:00
dependabot[bot]
29c204b2c2 Bump org.springframework.boot from 3.1.0 to 3.1.1
Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: org.springframework.boot
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-02 17:30:53 +00:00
dependabot[bot]
657e881963 Bump edu.sc.seis.launch4j from 3.0.1 to 3.0.3
Bumps edu.sc.seis.launch4j from 3.0.1 to 3.0.3.

---
updated-dependencies:
- dependency-name: edu.sc.seis.launch4j
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-02 17:30:51 +00:00
Anthony Stirling
ef6bdc70a4 Merge branch 'main' into dependabot/gradle/commons-io-commons-io-2.13.0 2023-07-02 18:30:35 +01:00
Anthony Stirling
e4a36115a2 Merge pull request #230 from Frooodle/dependabot/gradle/io.swagger.swaggerhub-1.2.0
Bump io.swagger.swaggerhub from 1.1.0 to 1.2.0
2023-07-02 18:30:19 +01:00
dependabot[bot]
325f86832c Bump commons-io:commons-io from 2.11.0 to 2.13.0
Bumps commons-io:commons-io from 2.11.0 to 2.13.0.

---
updated-dependencies:
- dependency-name: commons-io:commons-io
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-02 17:27:54 +00:00
dependabot[bot]
e3dbdd6b09 Bump io.swagger.swaggerhub from 1.1.0 to 1.2.0
Bumps io.swagger.swaggerhub from 1.1.0 to 1.2.0.

---
updated-dependencies:
- dependency-name: io.swagger.swaggerhub
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-02 17:27:54 +00:00
Anthony Stirling
919041e879 Update version and disable folder scan alpha 2023-07-02 18:27:23 +01:00
Anthony Stirling
182231a183 Merge pull request #256 from Frooodle/pipeline
Pipeline changes, fonts, and watermark fixes
2023-07-02 18:21:17 +01:00
Anthony Stirling
46d4ae8fc5 pipeline change 2023-07-02 18:20:23 +01:00
Anthony Stirling
73ab1936a3 filter update 2023-07-02 00:34:04 +01:00
Anthony Stirling
59c72527b5 remove from menu for now 2023-07-01 23:40:17 +01:00
Anthony Stirling
5ea3bcc1dd watermark stuff 2023-07-01 22:18:49 +01:00
Anthony Stirling
c140052822 watermark fix 2023-07-01 21:08:33 +01:00
Anthony Stirling
f7832774d9 cachec change 2023-06-29 23:59:15 +01:00
systo
279d25c03a Merge branch 'pipeline' of git@github.com:Frooodle/Stirling-PDF.git into pipeline 2023-06-29 23:34:22 +01:00
Anthony Stirling
f1984047a8 Update README.md 2023-06-29 22:03:31 +01:00
Anthony Stirling
eae7c1bd60 Update README.md 2023-06-29 22:02:59 +01:00
systo
d7f592ebda Merge remote-tracking branch 'origin/main' into pipeline 2023-06-29 22:01:49 +01:00
Anthony Stirling
1798ce002a Fix metrics 2023-06-29 21:51:08 +01:00
systo
57a0cca595 Merge remote-tracking branch 'origin/master' into pipeline 2023-06-29 19:13:33 +01:00
Anthony Stirling
b26fbd7693 Update README.md 2023-06-29 17:07:34 +01:00
Anthony Stirling
43b0e25bdb modes 2023-06-26 18:23:06 +01:00
Anthony Stirling
3377af1305 api tag 2023-06-25 09:16:32 +01:00
Anthony Stirling
c81c1006b7 Merge branch 'pipeline' of git@github.com:Frooodle/Stirling-PDF.git into
pipeline
2023-06-24 15:25:39 +01:00
systo
f313857f96 Merge branch 'pipeline' of git@github.com:Frooodle/Stirling-PDF.git into pipeline 2023-06-24 14:59:58 +01:00
Anthony Stirling
d5fbe02149 notosans arabic JP, KR SC 2023-06-24 14:59:49 +01:00
Anthony Stirling
159cee0b39 init many new shit 2023-06-23 23:29:53 +01:00
Alberto Pasqualetto
5da4dd6cca Fix addImages text 2023-06-23 00:11:26 +00:00
Anthony Stirling
e9daf05f16 pipeline cleanup 2023-06-21 21:41:58 +01:00
Anthony Stirling
a12643194a changes 2023-06-21 21:19:52 +01:00
Anthony Stirling
25d8fc08f7 Merge pull request #250 from inazkue/patch-1
Update navbar.html
2023-06-21 11:55:44 +01:00
inazkue
a72378dd4d Update navbar.html
fix navbar.html basque language item description
2023-06-21 11:10:50 +02:00
systo
9aed70408b Merge branch 'pipeline' of git@github.com:Frooodle/Stirling-PDF.git into pipeline 2023-06-20 23:50:05 +01:00
Anthony Stirling
5ae2c71c3a Input:PDF Output:PDF 2023-06-20 23:49:53 +01:00
Anthony Stirling
4edce515b8 Merge pull request #249 from inazkue/main
Basque language
2023-06-20 21:42:57 +01:00
Anthony Stirling
67ff664eb8 Delete messages_eu_EU.properties 2023-06-20 21:41:44 +01:00
inazkue
71c1a4f102 Update navbar.html 2023-06-20 14:44:37 +02:00
inazkue
ba4ba1b9fc Add files via upload 2023-06-20 14:38:11 +02:00
inazkue
59f10f06ca Add files via upload 2023-06-19 11:57:18 +02:00
inazkue
f7953cbc37 Add files via upload 2023-06-19 11:55:54 +02:00
Anthony Stirling
9a74e81754 text 2023-06-14 19:57:01 +01:00
Anthony Stirling
420e4b6766 fixes 2023-06-13 23:50:46 +01:00
Anthony Stirling
aed48ffc93 pipe 2023-06-13 19:18:40 +01:00
Anthony Stirling
0cebe69ff8 Pipeline init 2023-06-13 00:32:15 +01:00
Anthony Stirling
e5990dba81 Update Beans.java 2023-06-12 17:31:42 +01:00
Anthony Stirling
c9b0d01250 Update push-docker.yml 2023-06-12 16:20:14 +01:00
Anthony Stirling
4918ed3f3c Merge pull request #238 from tkymmm/japanese
Japanese
2023-06-12 11:02:28 +01:00
tkymmm
b176ce4251 Update navbar.html 2023-06-12 14:57:51 +09:00
tkymmm
518ff5409e Add files via upload 2023-06-12 14:56:45 +09:00
tkymmm
803bd3c5b2 Add files via upload 2023-06-12 14:56:05 +09:00
Anthony Stirling
03d4e73304 jar name change 2023-06-10 18:24:32 +01:00
Anthony Stirling
55a820b09f Update build.gradle 2023-06-10 18:20:28 +01:00
Anthony Stirling
f2a65dc360 Update build.gradle 2023-06-10 18:15:23 +01:00
Anthony Stirling
7b4a889ea7 Remove debugs 2023-06-10 18:14:34 +01:00
Anthony Stirling
f627d251c3 Update releaseArtifacts.yml 2023-06-10 18:06:59 +01:00
Anthony Stirling
d5b7125415 Rename app to Stirling-PDF not S-pdf 2023-06-10 18:04:06 +01:00
Anthony Stirling
67dd3cf0e3 Update releaseArtifacts.yml 2023-06-10 17:54:50 +01:00
Anthony Stirling
b8b62bb5af Update releaseArtifacts.yml 2023-06-10 17:44:02 +01:00
Anthony Stirling
b4a9d1ac18 Update releaseArtifacts.yml 2023-06-10 17:39:36 +01:00
Anthony Stirling
8aae651c2c Update releaseArtifacts.yml 2023-06-10 15:22:35 +01:00
Anthony Stirling
fc9465b324 Update releaseArtifacts.yml 2023-06-10 15:21:54 +01:00
Anthony Stirling
579a50be2c Update releaseArtifacts.yml 2023-06-10 15:15:51 +01:00
Anthony Stirling
9c5b967e4c fix 2023-06-10 15:10:37 +01:00
Anthony Stirling
d41deb729b fix for action 2023-06-10 15:07:20 +01:00
Anthony Stirling
a93a89f3f0 github action for release upload 2023-06-10 15:06:01 +01:00
Anthony Stirling
11d642a25f Upload jar and .exe to release 2023-06-10 15:05:38 +01:00
Anthony Stirling
67448498ea documentation stuff and downloer fix for image to pdf 2023-06-10 00:46:44 +01:00
Anthony Stirling
489b8da713 fix for actions 2023-06-08 22:28:13 +01:00
Anthony Stirling
728d4d0fa8 latest 2023-06-08 22:02:09 +01:00
Anthony Stirling
e70f4ff3a6 version bump 2023-06-08 20:45:35 +01:00
Anthony Stirling
04032c0dfe sign changes min size, lite docker, merge fix #172 2023-06-08 20:25:55 +01:00
Anthony Stirling
ecba6461df Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into
main
2023-06-07 14:47:06 +01:00
Anthony Stirling
433ba6c250 groups update 2023-06-07 14:13:18 +01:00
Anthony Stirling
ff6c55d1d0 fix naming issues in split and made it allign with others 2023-06-07 14:01:37 +01:00
Anthony Stirling
d9f8facf2e Merge pull request #232 from NeilJared/patch-1
Update messages_es_ES.properties
2023-06-06 00:26:20 +01:00
NeilJared
6bd3e5cc8f Update messages_es_ES.properties
Updated Spanish translation
2023-06-06 01:12:03 +02:00
Anthony Stirling
936fb5ae45 Update README.md 2023-06-05 23:08:55 +01:00
Anthony Stirling
8e661e1260 fix spanish remove blanks 2023-06-05 22:30:18 +01:00
Anthony Stirling
987d9b0502 Merge pull request #227 from jordyjordy/fix-imgtopdf-typo
fix typo in img conversion filename
2023-06-05 19:42:48 +01:00
Anthony Stirling
f6a9169446 Merge branch 'main' into fix-imgtopdf-typo 2023-06-05 19:41:24 +01:00
Anthony Stirling
d5c1c43eb1 Merge pull request #228 from jordyjordy/fix-multitool-filemixing
await pdf creation in each for loop.
2023-06-05 19:41:15 +01:00
Anthony Stirling
20c74dac60 Merge branch 'main' into fix-multitool-filemixing 2023-06-05 19:40:00 +01:00
Anthony Stirling
30161275a3 Merge branch 'main' into fix-imgtopdf-typo 2023-06-05 19:39:14 +01:00
jordy
7e9479806e await pdf creation in each for loop. 2023-06-05 19:38:25 +02:00
jordy
39b9ea9f1d fix typo 2023-06-05 19:25:36 +02:00
Anthony Stirling
5a9165d7c6 missing lang 2023-06-05 18:23:15 +01:00
Anthony Stirling
4f851156b7 dummy lang changes 2023-06-04 22:40:14 +01:00
Anthony Stirling
b8fa278173 finalise auto swagger docs 2023-06-03 23:32:47 +01:00
Anthony Stirling
2cfb344e13 swagger 2023-06-03 23:24:40 +01:00
Anthony Stirling
1d2bf92abe Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into
main
2023-06-03 23:21:47 +01:00
Anthony Stirling
cefcda9f40 test 2023-06-03 23:21:12 +01:00
Anthony Stirling
a4bc67ff8e Update swagger.yml 2023-06-03 23:08:10 +01:00
Anthony Stirling
48b3dea256 remove push 2023-06-03 23:05:20 +01:00
Anthony Stirling
1f5231d905 @./SwaggerDoc.json 2023-06-03 23:01:14 +01:00
Anthony Stirling
c526e18992 Split pages support n function and other stuff 2023-06-03 22:56:15 +01:00
Anthony Stirling
4594765cbd rearrange support n numbers, downloader.js fixes 2023-06-03 17:21:59 +01:00
Anthony Stirling
e2a787e519 Hide banner if mobile 2023-06-02 23:43:22 +01:00
Anthony Stirling
45b3e0aa6a JS and css cleanup 2023-06-02 20:15:10 +01:00
Anthony Stirling
7bdb2615d4 css cleanup 2023-06-01 23:12:55 +01:00
systo
019a502490 Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into main 2023-06-01 21:37:40 +01:00
Anthony Stirling
6793fd5bc7 thirs party js folder 2023-06-01 21:37:33 +01:00
systo
8ac5cf759e Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into main 2023-06-01 11:22:56 +01:00
Anthony Stirling
19880567ba Donation buttons 2023-06-01 11:22:44 +01:00
Anthony Stirling
5c5a3fefc1 Merge pull request #205 from Frooodle/dependabot/gradle/org.springframework.boot-spring-boot-starter-test-3.1.0
Bump org.springframework.boot:spring-boot-starter-test from 3.0.6 to 3.1.0
2023-06-01 10:53:13 +01:00
Anthony Stirling
90057828a5 Merge branch 'main' into dependabot/gradle/org.springframework.boot-spring-boot-starter-test-3.1.0 2023-06-01 10:52:24 +01:00
Anthony Stirling
7cfc3a09a2 Merge pull request #206 from Frooodle/dependabot/gradle/org.springframework.boot-3.1.0
Bump org.springframework.boot from 3.0.6 to 3.1.0
2023-06-01 10:52:08 +01:00
dependabot[bot]
b8bbee27f8 Bump org.springframework.boot:spring-boot-starter-test
Bumps [org.springframework.boot:spring-boot-starter-test](https://github.com/spring-projects/spring-boot) from 3.0.6 to 3.1.0.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-test
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 09:51:11 +00:00
Anthony Stirling
8e5c665e49 Merge branch 'main' into dependabot/gradle/org.springframework.boot-3.1.0 2023-06-01 10:50:49 +01:00
Anthony Stirling
7b1e6fb953 Merge pull request #204 from Frooodle/dependabot/gradle/org.springframework.boot-spring-boot-starter-thymeleaf-3.1.0
Bump org.springframework.boot:spring-boot-starter-thymeleaf from 3.0.6 to 3.1.0
2023-06-01 10:50:22 +01:00
dependabot[bot]
79936e69c5 Bump org.springframework.boot from 3.0.6 to 3.1.0
Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 3.0.6 to 3.1.0.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)

---
updated-dependencies:
- dependency-name: org.springframework.boot
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 09:49:33 +00:00
dependabot[bot]
a19cd327f3 Bump org.springframework.boot:spring-boot-starter-thymeleaf
Bumps [org.springframework.boot:spring-boot-starter-thymeleaf](https://github.com/spring-projects/spring-boot) from 3.0.6 to 3.1.0.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-thymeleaf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 09:49:26 +00:00
Anthony Stirling
5c831c156b Merge pull request #203 from Frooodle/dependabot/gradle/org.springframework.boot-spring-boot-starter-web-3.1.0
Bump org.springframework.boot:spring-boot-starter-web from 3.0.6 to 3.1.0
2023-06-01 10:48:55 +01:00
Anthony Stirling
602df08df5 Merge branch 'main' into dependabot/gradle/org.springframework.boot-spring-boot-starter-web-3.1.0 2023-06-01 10:48:04 +01:00
Anthony Stirling
3b8d06a9e3 Merge pull request #222 from MarcO-79/patch-14
Update messages_pl_PL.properties
2023-06-01 07:40:45 +01:00
Marcin Bielicki
5fd43b50e0 Update messages_pl_PL.properties
Adjusting the translation to the new version
2023-06-01 08:00:39 +02:00
Anthony Stirling
15d39413f3 scaled changes 2023-05-31 21:33:45 +01:00
systo
5e01946981 Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into main 2023-05-31 21:28:15 +01:00
Anthony Stirling
576d11f09a Download cleanup 2023-05-31 21:28:05 +01:00
Anthony Stirling
a43c296eef Merge pull request #221 from LaserKaspar/main
Scale Pages
2023-05-31 21:27:32 +01:00
Felix Kaspar
6015591e34 Language 2023-05-31 21:44:59 +02:00
Felix Kaspar
6f5f031b24 Scale Pages 2023-05-31 21:39:40 +02:00
Anthony Stirling
1499e78795 GeneralUtils 2023-05-31 20:37:13 +01:00
Anthony Stirling
1b45ab7222 util move around 2023-05-31 20:15:48 +01:00
Anthony Stirling
005b158ad3 naming fix 2023-05-31 18:44:32 +01:00
Anthony Stirling
26d003e840 css fix 2023-05-31 00:17:48 +01:00
Anthony Stirling
192fb39302 new error display logic init 2023-05-31 00:06:35 +01:00
dependabot[bot]
1650dfcc29 Bump org.springframework.boot:spring-boot-starter-web
Bumps [org.springframework.boot:spring-boot-starter-web](https://github.com/spring-projects/spring-boot) from 3.0.6 to 3.1.0.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-web
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-30 19:55:06 +00:00
Anthony Stirling
fda83c4c1d password fix init 2023-05-30 20:54:19 +01:00
systo
1a6ebbb8e5 Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into main 2023-05-30 19:46:09 +01:00
Anthony Stirling
ea1f8912b8 cert change remove requirement for para,s. pdf-to-img dpi fix 2023-05-30 19:45:51 +01:00
Anthony Stirling
a5885d2628 Merge pull request #218 from blairw/patch-1
Update LocalRunGuide.md
2023-05-29 23:27:57 +01:00
Blair Wang
716d4c6f28 Update LocalRunGuide.md
Correct small typo (`/build/libs/` does not exist, `./build/libs/` does)
2023-05-30 08:15:26 +10:00
Anthony Stirling
b3a36c82bb Merge pull request #215 from MarcO-79/patch-13
Update messages_pl_PL.properties
2023-05-29 14:02:43 +01:00
Marcin Bielicki
75fff1d52f Update messages_pl_PL.properties
Adjusting the translation to the new version
2023-05-29 13:34:20 +02:00
Anthony Stirling
2d88987cb3 Multi page layout init for #212 2023-05-27 14:23:25 +01:00
Anthony Stirling
8bbbdbd359 duplex 2023-05-26 23:53:11 +01:00
systo
8a2aa44de8 Merge branch 'main' of git@github.com:Frooodle/Stirling-PDF.git into main 2023-05-26 19:30:06 +01:00
Anthony Stirling
3715c555d3 fix for #213 2023-05-26 15:25:18 +01:00
Anthony Stirling
5e4de6cc5f some filename fixes for nicer extraction 2023-05-26 14:39:08 +01:00
Anthony Stirling
4cadfc64f6 Merge pull request #211 from itsfks/main
Adição tradução PT_BR
2023-05-26 10:15:35 +01:00
felipe
a3f0d47cad Adição tradução PT_BR 2023-05-25 20:49:04 -03:00
Anthony Stirling
bc55b5fdda Merge pull request #208 from MarcO-79/patch-12
Update messages_pl_PL.properties
2023-05-23 11:29:20 +01:00
Marcin Bielicki
43474712eb Update messages_pl_PL.properties
Corrections to the translation
2023-05-23 12:02:37 +02:00
141 changed files with 6361 additions and 1542 deletions

View File

@@ -8,7 +8,6 @@ on:
- main
jobs:
push:
runs-on: ubuntu-latest
steps:
@@ -46,13 +45,17 @@ jobs:
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Convert repository owner to lowercase
id: repoowner
run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')"
- name: Generate tags
id: meta
uses: docker/metadata-action@v4.4.0
with:
images: |
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
ghcr.io/${{ github.repository_owner }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
@@ -76,27 +79,27 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64/v8
- name: Generate tags
- name: Generate tags ultra-lite
id: meta2
uses: docker/metadata-action@v4.4.0
if: github.ref != 'refs/heads/main'
with:
images: |
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
ghcr.io/${{ github.repository_owner }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-light,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest-ultra-light,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=alpha-ultra-light,enable=${{ github.ref == 'refs/heads/main' }}
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
- name: Convert repository owner to lowercase
id: repoowner
run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')"
- name: Build and push Dockerfile-ultralite
- name: Build and push Dockerfile-ultra-lite
uses: docker/build-push-action@v4.0.0
if: github.ref != 'refs/heads/main'
with:
context: .
file: ./Dockerfile-ultralite
file: ./Dockerfile-ultra-lite
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
@@ -105,3 +108,29 @@ jobs:
platforms: linux/amd64,linux/arm64/v8
- name: Generate tags lite
id: meta3
uses: docker/metadata-action@v4.4.0
if: github.ref != 'refs/heads/main'
with:
images: |
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-lite,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest-lite,enable=${{ github.ref == 'refs/heads/master' }}
- name: Build and push Dockerfile-lite
uses: docker/build-push-action@v4.0.0
if: github.ref != 'refs/heads/main'
with:
context: .
file: ./Dockerfile-lite
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ${{ steps.meta3.outputs.tags }}
labels: ${{ steps.meta3.outputs.labels }}
platforms: linux/amd64,linux/arm64/v8

45
.github/workflows/releaseArtifacts.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Release Artifacts
on:
release:
types: [created]
jobs:
push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.5.2
- name: Set up JDK 17
uses: actions/setup-java@v3.11.0
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Generate jar
run: ./gradlew clean createExe
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./build/launch4j/Stirling-PDF.exe
asset_name: Stirling-PDF.exe
tag: ${{ github.ref }}
overwrite: true
- name: Get version number
id: versionNumber
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar
asset_name: Stirling-PDF.jar
tag: ${{ github.ref }}
overwrite: true

37
.github/workflows/swagger.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Update Swagger
on:
workflow_dispatch:
push:
branches:
- master
jobs:
push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.5.2
- name: Set up JDK 17
uses: actions/setup-java@v3.11.0
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Generate Swagger documentation
run: ./gradlew generateOpenApiDocs
- name: Upload Swagger Documentation to SwaggerHub
run: ./gradlew swaggerhubUpload
env:
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
- name: Set API version as published and default on SwaggerHub
run: |
curl -X PUT -H "Authorization: ${SWAGGERHUB_API_KEY}" "https://api.swaggerhub.com/apis/Frooodle/Stirling-PDF/${{ steps.versionNumber.outputs.versionNumber }}/settings/lifecycle" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"published\":true,\"default\":true}"
env:
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}

1
.gitignore vendored
View File

@@ -14,6 +14,7 @@ local.properties
.recommenders
.classpath
.project
version.properties
# Gradle
.gradle

View File

@@ -1,10 +1,16 @@
# Build jbig2enc in a separate stage
FROM frooodle/stirling-pdf-base:beta3
FROM frooodle/stirling-pdf-base:latest
# Create scripts folder and copy local scripts
RUN mkdir /scripts
COPY ./scripts/* /scripts/
#Install fonts
RUN mkdir /usr/share/fonts/opentype/noto/
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
RUN fc-cache -f -v
# Copy the application JAR file
COPY build/libs/*.jar app.jar

23
Dockerfile-lite Normal file
View File

@@ -0,0 +1,23 @@
# Build jbig2enc in a separate stage
FROM bellsoft/liberica-openjdk-debian:17
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libreoffice-core-nogui \
libreoffice-common \
libreoffice-writer-nogui \
libreoffice-calc-nogui \
libreoffice-impress-nogui \
unoconv && \
rm -rf /var/lib/apt/lists/*
# Copy the application JAR file
COPY build/libs/*.jar app.jar
# Expose the application port
EXPOSE 8080
# Set environment variables
ENV GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF
# Run the application
CMD ["java", "-jar", "/app.jar"]

View File

@@ -1,5 +1,5 @@
# Build jbig2enc in a separate stage
FROM openjdk:17-jdk-slim
FROM bellsoft/liberica-openjdk-alpine:17
# Copy the application JAR file
COPY build/libs/*.jar app.jar
@@ -8,7 +8,7 @@ COPY build/libs/*.jar app.jar
EXPOSE 8080
# Set environment variables
ENV GROUPS_TO_REMOVE=LibreOffice,CLI
ENV GROUPS_TO_REMOVE=CLI
# Run the application
CMD ["java", "-jar", "/app.jar"]

View File

@@ -1,5 +1,5 @@
# Main stage
FROM openjdk:17-jdk-slim AS base
FROM bellsoft/liberica-openjdk-debian:17 AS base
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libreoffice-core-nogui \

35
Endpoint-groups.md Normal file
View File

@@ -0,0 +1,35 @@
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------|
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
| split-pdfs | ✔️ | | | | | | | | | ✔️ | |
| file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | |
| xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| add-password | | | ✔️ | | | | | | | ✔️ | |
| add-watermark | | | ✔️ | | | | | | | ✔️ | |
| cert-sign | | | ✔️ | | | | | | | ✔️ | |
| change-permissions | | | ✔️ | | | | | | | ✔️ | |
| remove-password | | | ✔️ | | | | | | | ✔️ | |
| add-image | | | | ✔️ | | | | | | ✔️ | |
| change-metadata | | | | ✔️ | | | | | | ✔️ | |
| compare | | | | ✔️ | | | | | | | ✔️ |
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| extract-images | | | | ✔️ | | | | | | ✔️ | |
| flatten | | | | ✔️ | | | | | | | |
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
| sign | | | | ✔️ | | | | | | | ✔️ |

View File

@@ -123,7 +123,7 @@ This folder is required for the python scripts using OpenCV
```bash
sudo mkdir /opt/Stirling-PDF &&\
sudo mv /build/libs/S-PDF-*.jar /opt/Stirling-PDF/ &&\
sudo mv ./build/libs/Stirling-PDF-*.jar /opt/Stirling-PDF/ &&\
sudo mv scripts /opt/Stirling-PDF/ &&\
echo "Scripts installed."
```

View File

@@ -21,7 +21,7 @@ Feel free to request any features or bug fixes either in github issues or our [D
![stirling-home](images/stirling-home.png)
## Features
- Full intractable GUI for merging/splitting/rotating/moving PDFs and their pages.
- Full interactive GUI for merging/splitting/rotating/moving PDFs and their pages.
- Split PDFs into multiple files at specified page numbers or extract all pages as individual files.
- Merge multiple PDFs together into a single resultant file
- Convert PDFs to and from images
@@ -53,6 +53,7 @@ Hosted instance/demo of the app can be seen [here](https://pdf.adminforge.de/) h
## Technologies used
- Spring Boot + Thymeleaf
- PDFBox
- IText7
- [LibreOffice](https://www.libreoffice.org/discover/libreoffice/) for advanced conversions
- [OcrMyPdf](https://github.com/ocrmypdf/OCRmyPDF)
- HTML, CSS, JavaScript
@@ -68,13 +69,20 @@ Please view https://github.com/Frooodle/Stirling-PDF/blob/main/LocalRunGuide.md
### Docker
https://hub.docker.com/r/frooodle/s-pdf
Stirling PDF has 3 different versions, a Full version, Lite and ultra-Lite. 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/Frooodle/Stirling-PDF/blob/main/Version-groups.md)
For people that dont mind about space optimisation just use 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-lite?label=Stirling-PDF%20Lite)
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/frooodle/s-pdf/latest-ultra-lite?label=Stirling-PDF%20Ultra-Lite)
Docker Run
```
docker run -d \
-p 8080:8080 \
-v /location/of/trainingData:/usr/share/tesseract-ocr/4.00/tessdata \
--name stirling-pdf \
frooodle/s-pdf
frooodle/s-pdf:latest
Can also add these for customisation but are not required
@@ -90,7 +98,7 @@ Docker Compose
version: '3.3'
services:
stirling-pdf:
image: frooodle/s-pdf
image: frooodle/s-pdf:latest
ports:
- '8080:8080'
volumes:
@@ -111,7 +119,7 @@ services:
Please view https://github.com/Frooodle/Stirling-PDF/blob/main/HowToUseOCR.md
## Want to add your own language?
Stirling PDF currently supports
Stirling PDF currently supports 16!
- English (English) (en_GB)
- Arabic (العربية) (ar_AR)
- German (Deutsch) (de_DE)
@@ -124,6 +132,10 @@ Stirling PDF currently supports
- Polish (Polski) (pl_PL)
- Romanian (Română) (ro_RO)
- Korean (한국어) (ko_KR)
- Portuguese Brazilian (Português) (pt_BR)
- Russian (Русский) (ru_RU)
- Basque (Euskara) (eu_ES)
- Japanese (日本語) (ja_JP)
If you want to add your own language to Stirling-PDF please refer
https://github.com/Frooodle/Stirling-PDF/blob/main/HowToAddNewLanguage.md

48
Version-groups.md Normal file
View File

@@ -0,0 +1,48 @@
|Technology | Ultra-Lite | Lite | Full |
|----------------|:----------:|:----:|:----:|
| Java | ✔️ | ✔️ | ✔️ |
| JavaScript | ✔️ | ✔️ | ✔️ |
| Libre | | ✔️ | ✔️ |
| Python | | | ✔️ |
| OpenCV | | | ✔️ |
| OCRmyPDF | | | ✔️ |
Operation | Ultra-Lite | Lite | Full
--------------------|------------|------|-----
add-password | ✔️ | ✔️ | ✔️
add-watermark | ✔️ | ✔️ | ✔️
cert-sign | ✔️ | ✔️ | ✔️
change-metadata | ✔️ | ✔️ | ✔️
change-permissions | ✔️ | ✔️ | ✔️
compare | ✔️ | ✔️ | ✔️
extract-images | ✔️ | ✔️ | ✔️
flatten | ✔️ | ✔️ | ✔️
img-to-pdf | ✔️ | ✔️ | ✔️
merge-pdfs | ✔️ | ✔️ | ✔️
multi-page-layout | ✔️ | ✔️ | ✔️
pdf-organizer | ✔️ | ✔️ | ✔️
pdf-to-img | ✔️ | ✔️ | ✔️
remove-pages | ✔️ | ✔️ | ✔️
remove-password | ✔️ | ✔️ | ✔️
rotate-pdf | ✔️ | ✔️ | ✔️
scale-pages | ✔️ | ✔️ | ✔️
sign | ✔️ | ✔️ | ✔️
split-pdfs | ✔️ | ✔️ | ✔️
add-image | ✔️ | ✔️ | ✔️
file-to-pdf | | ✔️ | ✔️
pdf-to-html | | ✔️ | ✔️
pdf-to-presentation | | ✔️ | ✔️
pdf-to-text | | ✔️ | ✔️
pdf-to-word | | ✔️ | ✔️
pdf-to-xml | | ✔️ | ✔️
repair | | ✔️ | ✔️
xlsx-to-pdf | | ✔️ | ✔️
compress-pdf | | | ✔️
extract-image-scans | | | ✔️
ocr-pdf | | | ✔️
pdf-to-pdfa | | | ✔️
remove-blanks | | | ✔️

View File

@@ -1,24 +1,56 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.6'
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
id 'org.springdoc.openapi-gradle-plugin' version '1.6.0'
id "io.swagger.swaggerhub" version "1.2.0"
id 'edu.sc.seis.launch4j' version '3.0.3'
}
group = 'stirling.software'
version = '0.9.1'
version = '0.10.3'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
openApi {
apiDocsUrl = "http://localhost:8080/v3/api-docs"
outputDir = file("$projectDir")
outputFileName = "SwaggerDoc.json"
}
launch4j {
icon = "${projectDir}/src/main/resources/static/favicon.ico"
outfile="Stirling-PDF.exe"
headerType="console"
jarTask = tasks.bootJar
errTitle="Encountered error, Do you have Java 17?"
downloadUrl="https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe"
variables=["BROWSER_OPEN=true"]
jreMinVersion="17"
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 17."
messagesLauncherError="Java is corrupted. Please uninstall and then install Java 17."
messagesInstanceAlreadyExists="Stirling-PDF is already running."
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:3.0.6'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.0.6'
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.0.6'
implementation 'org.springframework.boot:spring-boot-starter-web:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.1'
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.0'
// https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
implementation 'commons-io:commons-io:2.11.0'
implementation 'commons-io:commons-io:2.13.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
@@ -34,6 +66,25 @@ dependencies {
}
task writeVersion {
def propsFile = file('src/main/resources/version.properties')
def props = new Properties()
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)
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
}
jar {
enabled = false
manifest {

View File

@@ -1,32 +0,0 @@
Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript
--------------------|---------|---------|----------|-------|------|--------|--------|-------------|--------- |-------- |-----------
remove-pages | X | | | | | | | | | X |
merge-pdfs | X | | | | | | | | | X |
split-pdfs | X | | | | | | | | | X |
pdf-organizer | X | | | | | | | | | X | X
rotate-pdf | X | | | | | | | | | X |
pdf-to-img | | X | | | | | | | | X |
img-to-pdf | | X | | | | | | | | X |
pdf-to-pdfa | | X | | | X | | | | X | |
file-to-pdf | | X | | | X | | | X | | |
xlsx-to-pdf | | X | | | X | | | X | | |
pdf-to-word | | X | | | X | | | X | | |
pdf-to-presentation | | X | | | X | | | X | | |
pdf-to-text | | X | | | X | | | X | | |
pdf-to-html | | X | | | X | | | X | | |
pdf-to-xml | | X | | | X | | | X | | |
add-password | | | X | | | | | | | X |
remove-password | | | X | | | | | | | X |
change-permissions | | | X | | | | | | | X |
add-watermark | | | X | | | | | | | X |
ocr-pdf | | | | X | X | | | | X | |
add-image | | | | X | | | | | | X |
compress-pdf | | | | X | X | | | | X
extract-images | | | | X | | | | | | X |
change-metadata | | | | X | | | | | | X |
extract-image-scans | | | | X | X | X | X | | | |
sign | | | | X | | | | | | | X
flatten | | | | X | | | | | | |
repair | | | | X | X | | | X | | |
remove-blanks | | | | X | X | X | X | | | |
compare | | | | X | | | | | | | X

36
lauch4jConfig.xml Normal file
View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<launch4jConfig>
<dontWrapJar>false</dontWrapJar>
<headerType>console</headerType>
<jar>.\build\libs\S-PDF-0.10.1.jar</jar>
<outfile>.\Stirling-PDF.exe</outfile>
<errTitle>Please download Java17</errTitle>
<cmdLine></cmdLine>
<chdir>.</chdir>
<priority>normal</priority>
<downloadUrl>https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe</downloadUrl>
<supportUrl></supportUrl>
<stayAlive>false</stayAlive>
<restartOnCrash>false</restartOnCrash>
<manifest></manifest>
<icon>./src/main/resources/static/favicon.ico</icon>
<var>BROWSER_OPEN=true</var>
<singleInstance>
<mutexName>Stirling-PDF</mutexName>
<windowTitle>Stirling-PDF</windowTitle>
</singleInstance>
<jre>
<path>%JAVA_HOME%;%PATH%</path>
<requiresJdk>false</requiresJdk>
<requires64Bit>false</requires64Bit>
<minVersion>17</minVersion>
<maxVersion></maxVersion>
</jre>
<messages>
<startupErr>An error occurred while starting Stirling-PDF</startupErr>
<jreNotFoundErr>This application requires a Java Runtime Environment, Please download Java 17.</jreNotFoundErr>
<jreVersionErr>You are running the wrong version of Java, Please download Java 17.</jreVersionErr>
<launcherErr>Java is corrupted. Please uninstall and then install Java 17.</launcherErr>
<instanceAlreadyExistsMsg>Stirling-PDF is already running.</instanceAlreadyExistsMsg>
</messages>
</launch4jConfig>

View File

@@ -14,13 +14,21 @@ def is_blank_image(image_path, threshold=10, white_percent=99, white_value=255,
blurred_image = cv2.GaussianBlur(image, (blur_size, blur_size), 0)
_, thresholded_image = cv2.threshold(blurred_image, white_value - threshold, white_value, cv2.THRESH_BINARY)
# Calculate the percentage of white pixels in the thresholded image
white_pixels = np.sum(thresholded_image == white_value)
white_pixels = 0
total_pixels = thresholded_image.size
white_pixel_percentage = (white_pixels / total_pixels) * 100
for i in range(0, thresholded_image.shape[0], 2):
for j in range(0, thresholded_image.shape[1], 2):
if thresholded_image[i, j] == white_value:
white_pixels += 1
white_pixel_percentage = (white_pixels / (i * thresholded_image.shape[1] + j + 1)) * 100
if white_pixel_percentage < white_percent:
return False
print(f"Page has white pixel percent of {white_pixel_percentage}")
return white_pixel_percentage > white_percent
return True
if __name__ == "__main__":

View File

@@ -1 +1 @@
rootProject.name = 'S-PDF'
rootProject.name = 'Stirling-PDF'

View File

@@ -1,11 +1,63 @@
package stirling.software.SPDF;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;
import jakarta.annotation.PostConstruct;
@SpringBootApplication
//@EnableScheduling
public class SPdfApplication {
@Autowired
private Environment env;
@PostConstruct
public void init() {
// Check if the BROWSER_OPEN environment variable is set to true
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
boolean browserOpen = browserOpenEnv != null && browserOpenEnv.equalsIgnoreCase("true");
if (browserOpen) {
try {
String port = env.getProperty("local.server.port");
if(port == null || port.length() == 0) {
port="8080";
}
String url = "http://localhost:" + port;
String os = System.getProperty("os.name").toLowerCase();
Runtime rt = Runtime.getRuntime();
if (os.contains("win")) {
// For Windows
rt.exec("rundll32 url.dll,FileProtocolHandler " + url);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SpringApplication.run(SPdfApplication.class, args);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Stirling-PDF Started.");
String port = System.getProperty("local.server.port");
if(port == null || port.length() == 0) {
port="8080";
}
String url = "http://localhost:" + port;
System.out.println("Navigate to " + url);
}
}

View File

@@ -16,7 +16,7 @@ public class AppConfig {
@Bean(name = "appVersion")
public String appVersion() {
String version = getClass().getPackage().getImplementationVersion();
return (version != null) ? version : "0.3.3";
return (version != null) ? version : "0.0.0";
}
@Bean(name = "homeText")

View File

@@ -39,10 +39,17 @@ public class Beans implements WebMvcConfigurer {
Locale tempLocale = Locale.forLanguageTag(appLocaleEnv);
String tempLanguageTag = tempLocale.toLanguageTag();
if (appLocaleEnv.equalsIgnoreCase(tempLanguageTag)) {
if (appLocaleEnv.equalsIgnoreCase(tempLanguageTag)) {
defaultLocale = tempLocale;
} else {
System.err.println("Invalid APP_LOCALE environment variable value. Falling back to default Locale.UK.");
tempLocale = Locale.forLanguageTag(appLocaleEnv.replace("_","-"));
tempLanguageTag = tempLocale.toLanguageTag();
if (appLocaleEnv.equalsIgnoreCase(tempLanguageTag)) {
defaultLocale = tempLocale;
} else {
System.err.println("Invalid APP_LOCALE environment variable value. Falling back to default Locale.UK.");
}
}
}

View File

@@ -1,4 +1,6 @@
package stirling.software.SPDF.config;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -7,39 +9,71 @@ import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Arrays;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class CleanUrlInterceptor implements HandlerInterceptor {
private static final Pattern LANG_PATTERN = Pattern.compile("&?lang=([^&]+)");
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) {
String requestURI = request.getRequestURI();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) {
String requestURI = request.getRequestURI();
// Keep the lang parameter if it exists
Matcher langMatcher = LANG_PATTERN.matcher(queryString);
String langQueryString = langMatcher.find() ? "lang=" + langMatcher.group(1) : "";
Map<String, String> parameters = new HashMap<>();
// Check if there are any other query parameters besides the lang parameter
String remainingQueryString = queryString.replaceAll(LANG_PATTERN.pattern(), "").replaceAll("&+", "&").replaceAll("^&|&$", "");
// Keep only the allowed parameters
String[] queryParameters = queryString.split("&");
for (String param : queryParameters) {
String[] keyValue = param.split("=");
if (keyValue.length != 2) {
continue;
}
if (ALLOWED_PARAMS.contains(keyValue[0])) {
parameters.put(keyValue[0], keyValue[1]);
}
}
if (!remainingQueryString.isEmpty()) {
// Redirect to the URL without other query parameters
String redirectUrl = requestURI + (langQueryString.isEmpty() ? "" : "?" + langQueryString);
response.sendRedirect(redirectUrl);
return false;
}
}
return true;
}
// If there are any parameters that are not allowed
if (parameters.size() != queryParameters.length) {
// Construct new query string
StringBuilder newQueryString = new StringBuilder();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (newQueryString.length() > 0) {
newQueryString.append("&");
}
newQueryString.append(entry.getKey()).append("=").append(entry.getValue());
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
}
// Redirect to the URL with only allowed query parameters
String redirectUrl = requestURI + "?" + newQueryString;
response.sendRedirect(redirectUrl);
return false;
}
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
}
}

View File

@@ -20,12 +20,14 @@ public class EndpointConfiguration {
}
public void enableEndpoint(String endpoint) {
endpointStatuses.put(endpoint, true);
endpointStatuses.put(endpoint, true);
}
public void disableEndpoint(String endpoint) {
logger.info("Disabling {}", endpoint);
endpointStatuses.put(endpoint, false);
if(!endpointStatuses.containsKey(endpoint) || endpointStatuses.get(endpoint) != false) {
logger.info("Disabling {}", endpoint);
endpointStatuses.put(endpoint, false);
}
}
public boolean isEndpointEnabled(String endpoint) {
@@ -64,7 +66,9 @@ public class EndpointConfiguration {
addEndpointToGroup("PageOps", "split-pdfs");
addEndpointToGroup("PageOps", "pdf-organizer");
addEndpointToGroup("PageOps", "rotate-pdf");
addEndpointToGroup("PageOps", "multi-page-layout");
addEndpointToGroup("PageOps", "scale-pages");
// Adding endpoints to "Convert" group
addEndpointToGroup("Convert", "pdf-to-img");
addEndpointToGroup("Convert", "img-to-pdf");
@@ -82,6 +86,9 @@ public class EndpointConfiguration {
addEndpointToGroup("Security", "remove-password");
addEndpointToGroup("Security", "change-permissions");
addEndpointToGroup("Security", "add-watermark");
addEndpointToGroup("Security", "cert-sign");
// Adding endpoints to "Other" group
addEndpointToGroup("Other", "ocr-pdf");
@@ -158,6 +165,9 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "add-image");
addEndpointToGroup("Java", "extract-images");
addEndpointToGroup("Java", "change-metadata");
addEndpointToGroup("Java", "cert-sign");
addEndpointToGroup("Java", "multi-page-layout");
addEndpointToGroup("Java", "scale-pages");
//Javascript

View File

@@ -27,7 +27,8 @@ public class MetricsFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String uri = request.getRequestURI();
//System.out.println("uri="+uri + ", method=" + request.getMethod() );
// Ignore static resources
if (!(uri.startsWith("/js") || uri.startsWith("/images") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) {
Counter counter = Counter.builder("http.requests")
@@ -36,6 +37,7 @@ public class MetricsFilter extends OncePerRequestFilter {
.register(meterRegistry);
counter.increment();
//System.out.println("Counted");
}
filterChain.doFilter(request, response);

View File

@@ -1,5 +1,9 @@
package stirling.software.SPDF.config;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -10,13 +14,23 @@ import io.swagger.v3.oas.models.info.Info;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
String version = getClass().getPackage().getImplementationVersion();
version = (version != null) ? version : "1.0.0";
return new OpenAPI().components(new Components()).info(
new Info().title("Stirling PDF API").version(version).description("API documentation for all Server-Side processing.\nPlease note some functionality might be UI only and missing from here."));
}
@Bean
public OpenAPI customOpenAPI() {
String version = getClass().getPackage().getImplementationVersion();
if (version == null) {
Properties props = new Properties();
try (InputStream input = getClass().getClassLoader().getResourceAsStream("version.properties")) {
props.load(input);
version = props.getProperty("version");
} catch (IOException ex) {
ex.printStackTrace();
version = "1.0.0"; // default version if all else fails
}
}
return new OpenAPI().components(new Components()).info(
new Info().title("Stirling PDF API").version(version).description("API documentation for all Server-Side processing.\nPlease note some functionality might be UI only and missing from here."));
}
}

View File

@@ -17,9 +17,11 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "General", description = "General APIs")
public class MergeController {
private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
@@ -47,7 +49,7 @@ public class MergeController {
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
@Operation(
summary = "Merge multiple PDF files into one",
description = "This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided."
description = "This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided. Input:PDF Output:PDF Type:MISO"
)
public ResponseEntity<byte[]> mergePdfs(
@RequestPart(required = true, value = "fileInput")
@@ -65,7 +67,7 @@ public class MergeController {
// Return the merged PDF as a response
ResponseEntity<byte[]> response = PdfUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
ResponseEntity<byte[]> response = WebResponseUtils.pdfDocToWebResponse(mergedDoc, files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
for (PDDocument doc : documents) {
// Close the document after processing

View File

@@ -0,0 +1,101 @@
package stirling.software.SPDF.controller.api;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "General", description = "General APIs")
public class MultiPageLayoutController {
private static final Logger logger = LoggerFactory.getLogger(MultiPageLayoutController.class);
@PostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
@Operation(summary = "Merge multiple pages of a PDF document into a single page", description = "This operation takes an input PDF file and the number of pages to merge into a single sheet in the output PDF file. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> mergeMultiplePagesIntoOne(
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
@Parameter(description = "The number of pages to fit onto a single sheet in the output PDF. Acceptable values are 2, 3, 4, 9, 16.", required = true, schema = @Schema(type = "integer", allowableValues = {
"2", "3", "4", "9", "16" })) @RequestParam("pagesPerSheet") int pagesPerSheet)
throws IOException {
if (pagesPerSheet != 2 && pagesPerSheet != 3
&& pagesPerSheet != (int) Math.sqrt(pagesPerSheet) * Math.sqrt(pagesPerSheet)) {
throw new IllegalArgumentException("pagesPerSheet must be 2, 3 or a perfect square");
}
int cols = pagesPerSheet == 2 || pagesPerSheet == 3 ? pagesPerSheet : (int) Math.sqrt(pagesPerSheet);
int rows = pagesPerSheet == 2 || pagesPerSheet == 3 ? 1 : (int) Math.sqrt(pagesPerSheet);
byte[] bytes = file.getBytes();
PdfReader reader = new PdfReader(new ByteArrayInputStream(bytes));
PdfDocument pdfDoc = new PdfDocument(reader);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = new PdfWriter(baos);
PdfDocument outputPdf = new PdfDocument(writer);
PageSize pageSize = new PageSize(PageSize.A4.rotate());
int totalPages = pdfDoc.getNumberOfPages();
float cellWidth = pageSize.getWidth() / cols;
float cellHeight = pageSize.getHeight() / rows;
for (int i = 1; i <= totalPages; i += pagesPerSheet) {
PdfPage page = outputPdf.addNewPage(pageSize);
PdfCanvas pdfCanvas = new PdfCanvas(page);
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
int index = i + row * cols + col;
if (index <= totalPages) {
// Get the page and calculate scaling factors
Rectangle rect = pdfDoc.getPage(index).getPageSize();
float scaleWidth = cellWidth / rect.getWidth();
float scaleHeight = cellHeight / rect.getHeight();
float scale = Math.min(scaleWidth, scaleHeight);
PdfFormXObject formXObject = pdfDoc.getPage(index).copyAsFormXObject(outputPdf);
float x = col * cellWidth + (cellWidth - rect.getWidth() * scale) / 2;
float y = (rows - 1 - row) * cellHeight + (cellHeight - rect.getHeight() * scale) / 2;
// Save the graphics state, apply the transformations, add the object, and then
// restore the graphics state
pdfCanvas.saveState();
pdfCanvas.concatMatrix(scale, 0, 0, scale, x, y);
pdfCanvas.addXObject(formXObject, 0, 0);
pdfCanvas.restoreState();
}
}
}
}
outputPdf.close();
byte[] pdfContent = baos.toByteArray();
pdfDoc.close();
return WebResponseUtils.bytesToWebResponse(pdfContent, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_layoutChanged.pdf");
}
}

View File

@@ -17,111 +17,193 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "General", description = "General APIs")
public class RearrangePagesPDFController {
private static final Logger logger = LoggerFactory.getLogger(RearrangePagesPDFController.class);
private static final Logger logger = LoggerFactory.getLogger(RearrangePagesPDFController.class);
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@Operation(summary = "Remove pages from a PDF file", description = "This endpoint removes specified pages from a given PDF file. Users can provide a comma-separated list of page numbers or ranges to delete. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> deletePages(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file from which pages will be removed") MultipartFile pdfFile,
@RequestParam("pagesToDelete") @Parameter(description = "Comma-separated list of pages or page ranges to delete, e.g., '1,3,5-8'") String pagesToDelete)
throws IOException {
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@Operation(summary = "Remove pages from a PDF file",
description = "This endpoint removes specified pages from a given PDF file. Users can provide a comma-separated list of page numbers or ranges to delete.")
public ResponseEntity<byte[]> deletePages(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file from which pages will be removed")
MultipartFile pdfFile,
@RequestParam("pagesToDelete")
@Parameter(description = "Comma-separated list of pages or page ranges to delete, e.g., '1,3,5-8'")
String pagesToDelete) throws IOException {
PDDocument document = PDDocument.load(pdfFile.getBytes());
PDDocument document = PDDocument.load(pdfFile.getBytes());
// Split the page order string into an array of page numbers or range of numbers
String[] pageOrderArr = pagesToDelete.split(",");
// Split the page order string into an array of page numbers or range of numbers
String[] pageOrderArr = pagesToDelete.split(",");
List<Integer> pagesToRemove = GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages());
List<Integer> pagesToRemove = pageOrderToString(pageOrderArr, document.getNumberOfPages());
for (int i = pagesToRemove.size() - 1; i >= 0; i--) {
int pageIndex = pagesToRemove.get(i);
document.removePage(pageIndex);
}
return WebResponseUtils.pdfDocToWebResponse(document,
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_pages.pdf");
for (int i = pagesToRemove.size() - 1; i >= 0; i--) {
int pageIndex = pagesToRemove.get(i);
document.removePage(pageIndex);
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_pages.pdf");
}
}
private enum CustomMode {
REVERSE_ORDER, DUPLEX_SORT, BOOKLET_SORT, ODD_EVEN_SPLIT, REMOVE_FIRST, REMOVE_LAST, REMOVE_FIRST_AND_LAST,
}
private List<Integer> pageOrderToString(String[] pageOrderArr, int totalPages) {
List<Integer> newPageOrder = new ArrayList<>();
// loop through the page order array
for (String element : pageOrderArr) {
// check if the element contains a range of pages
if (element.contains("-")) {
// split the range into start and end page
String[] range = element.split("-");
int start = Integer.parseInt(range[0]);
int end = Integer.parseInt(range[1]);
// check if the end page is greater than total pages
if (end > totalPages) {
end = totalPages;
}
// loop through the range of pages
for (int j = start; j <= end; j++) {
// print the current index
newPageOrder.add(j - 1);
}
} else {
// if the element is a single page
newPageOrder.add(Integer.parseInt(element) - 1);
}
}
private List<Integer> removeFirst(int totalPages) {
if (totalPages <= 1)
return new ArrayList<>();
List<Integer> newPageOrder = new ArrayList<>();
for (int i = 2; i <= totalPages; i++) {
newPageOrder.add(i - 1);
}
return newPageOrder;
}
return newPageOrder;
}
private List<Integer> removeLast(int totalPages) {
if (totalPages <= 1)
return new ArrayList<>();
List<Integer> newPageOrder = new ArrayList<>();
for (int i = 1; i < totalPages; i++) {
newPageOrder.add(i - 1);
}
return newPageOrder;
}
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
@Operation(summary = "Rearrange pages in a PDF file",
description = "This endpoint rearranges pages in a given PDF file based on the specified page order. Users can provide a page order as a comma-separated list of page numbers or page ranges.")
public ResponseEntity<byte[]> rearrangePages(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to rearrange pages")
MultipartFile pdfFile,
@RequestParam("pageOrder")
@Parameter(description = "The new page order as a comma-separated list of page numbers or page ranges (e.g., '1,3,5-7')")
String pageOrder) {
try {
// Load the input PDF
PDDocument document = PDDocument.load(pdfFile.getInputStream());
private List<Integer> removeFirstAndLast(int totalPages) {
if (totalPages <= 2)
return new ArrayList<>();
List<Integer> newPageOrder = new ArrayList<>();
for (int i = 2; i < totalPages; i++) {
newPageOrder.add(i - 1);
}
return newPageOrder;
}
// Split the page order string into an array of page numbers or range of numbers
String[] pageOrderArr = pageOrder.split(",");
// int[] newPageOrder = new int[pageOrderArr.length];
int totalPages = document.getNumberOfPages();
private List<Integer> reverseOrder(int totalPages) {
List<Integer> newPageOrder = new ArrayList<>();
for (int i = totalPages; i >= 1; i--) {
newPageOrder.add(i - 1);
}
return newPageOrder;
}
List<Integer> newPageOrder = pageOrderToString(pageOrderArr, totalPages);
private List<Integer> duplexSort(int totalPages) {
List<Integer> newPageOrder = new ArrayList<>();
int half = (totalPages + 1) / 2; // This ensures proper behavior with odd numbers of pages
for (int i = 1; i <= half; i++) {
newPageOrder.add(i - 1);
if (i <= totalPages - half) { // Avoid going out of bounds
newPageOrder.add(totalPages - i);
}
}
return newPageOrder;
}
// Create a new list to hold the pages in the new order
List<PDPage> newPages = new ArrayList<>();
for (int i = 0; i < newPageOrder.size(); i++) {
newPages.add(document.getPage(newPageOrder.get(i)));
}
private List<Integer> bookletSort(int totalPages) {
List<Integer> newPageOrder = new ArrayList<>();
for (int i = 0; i < totalPages / 2; i++) {
newPageOrder.add(i);
newPageOrder.add(totalPages - i - 1);
}
return newPageOrder;
}
// Remove all the pages from the original document
for (int i = document.getNumberOfPages() - 1; i >= 0; i--) {
document.removePage(i);
}
private List<Integer> oddEvenSplit(int totalPages) {
List<Integer> newPageOrder = new ArrayList<>();
for (int i = 1; i <= totalPages; i += 2) {
newPageOrder.add(i - 1);
}
for (int i = 2; i <= totalPages; i += 2) {
newPageOrder.add(i - 1);
}
return newPageOrder;
}
// Add the pages in the new order
for (PDPage page : newPages) {
document.addPage(page);
}
private List<Integer> processCustomMode(String customMode, int totalPages) {
try {
CustomMode mode = CustomMode.valueOf(customMode.toUpperCase());
switch (mode) {
case REVERSE_ORDER:
return reverseOrder(totalPages);
case DUPLEX_SORT:
return duplexSort(totalPages);
case BOOKLET_SORT:
return bookletSort(totalPages);
case ODD_EVEN_SPLIT:
return oddEvenSplit(totalPages);
case REMOVE_FIRST:
return removeFirst(totalPages);
case REMOVE_LAST:
return removeLast(totalPages);
case REMOVE_FIRST_AND_LAST:
return removeFirstAndLast(totalPages);
default:
throw new IllegalArgumentException("Unsupported custom mode");
}
} catch (IllegalArgumentException e) {
logger.error("Unsupported custom mode", e);
return null;
}
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rearranged.pdf");
} catch (IOException e) {
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
@Operation(summary = "Rearrange pages in a PDF file", description = "This endpoint rearranges pages in a given PDF file based on the specified page order or custom mode. Users can provide a page order as a comma-separated list of page numbers or page ranges, or a custom mode. Input:PDF Output:PDF")
public ResponseEntity<byte[]> rearrangePages(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to rearrange pages") MultipartFile pdfFile,
@RequestParam(required = false, value = "pageOrder") @Parameter(description = "The new page order as a comma-separated list of page numbers, page ranges (e.g., '1,3,5-7'), or functions in the format 'an+b' where 'a' is the multiplier of the page number 'n', and 'b' is a constant (e.g., '2n+1', '3n', '6n-5')") String pageOrder,
@RequestParam(required = false, value = "customMode") @Parameter(schema = @Schema(implementation = CustomMode.class, description = "The custom mode for page rearrangement. "
+ "Valid values are:\n" + "REVERSE_ORDER: Reverses the order of all pages.\n"
+ "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"
+ "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")) String customMode) {
try {
// Load the input PDF
PDDocument document = PDDocument.load(pdfFile.getInputStream());
logger.error("Failed rearranging documents", e);
return null;
}
}
// Split the page order string into an array of page numbers or range of numbers
String[] pageOrderArr = pageOrder != null ? pageOrder.split(",") : new String[0];
int totalPages = document.getNumberOfPages();
System.out.println("pageOrder=" + pageOrder);
System.out.println("customMode length =" + customMode.length());
List<Integer> newPageOrder;
if (customMode != null && customMode.length() > 0) {
newPageOrder = processCustomMode(customMode, totalPages);
} else {
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages);
}
// Create a new list to hold the pages in the new order
List<PDPage> newPages = new ArrayList<>();
for (int i = 0; i < newPageOrder.size(); i++) {
newPages.add(document.getPage(newPageOrder.get(i)));
}
// Remove all the pages from the original document
for (int i = document.getNumberOfPages() - 1; i >= 0; i--) {
document.removePage(i);
}
// Add the pages in the new order
for (PDPage page : newPages) {
document.addPage(page);
}
return WebResponseUtils.pdfDocToWebResponse(document,
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rearranged.pdf");
} catch (IOException e) {
logger.error("Failed rearranging documents", e);
return null;
}
}
}

View File

@@ -16,9 +16,11 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "General", description = "General APIs")
public class RotationController {
private static final Logger logger = LoggerFactory.getLogger(RotationController.class);
@@ -26,7 +28,7 @@ public class RotationController {
@PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
@Operation(
summary = "Rotate a PDF file",
description = "This endpoint rotates a given PDF file by a specified angle. The angle must be a multiple of 90."
description = "This endpoint rotates a given PDF file by a specified angle. The angle must be a multiple of 90. Input:PDF Output:PDF Type:SISO"
)
public ResponseEntity<byte[]> rotatePDF(
@RequestPart(required = true, value = "fileInput")
@@ -46,7 +48,7 @@ public class RotationController {
page.setRotation(page.getRotation() + angle);
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf");
return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf");
}

View File

@@ -0,0 +1,243 @@
package stirling.software.SPDF.controller.api;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.EventType;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData;
import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IEventListener;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "General", description = "General APIs")
public class ScalePagesController {
private static final Logger logger = LoggerFactory.getLogger(ScalePagesController.class);
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data")
@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> scalePages(
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
@Parameter(description = "The scale of pages in the output PDF. Acceptable values are A0-A10, B0-B9, LETTER, TABLOID, LEDGER, LEGAL, EXECUTIVE.", required = true, schema = @Schema(type = "String", allowableValues = {
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "B0", "B1", "B2", "B3", "B4",
"B5", "B6", "B7", "B8", "B9", "LETTER", "TABLOID", "LEDGER", "LEGAL",
"EXECUTIVE" })) @RequestParam("pageSize") String targetPageSize,
@Parameter(description = "The scale of the content on the pages of the output PDF. Acceptable values are floats.", required = true, schema = @Schema(type = "float")) @RequestParam("scaleFactor") float scaleFactor)
throws IOException {
Map<String, PageSize> sizeMap = new HashMap<>();
// Add A0 - A10
sizeMap.put("A0", PageSize.A0);
sizeMap.put("A1", PageSize.A1);
sizeMap.put("A2", PageSize.A2);
sizeMap.put("A3", PageSize.A3);
sizeMap.put("A4", PageSize.A4);
sizeMap.put("A5", PageSize.A5);
sizeMap.put("A6", PageSize.A6);
sizeMap.put("A7", PageSize.A7);
sizeMap.put("A8", PageSize.A8);
sizeMap.put("A9", PageSize.A9);
sizeMap.put("A10", PageSize.A10);
// Add B0 - B9
sizeMap.put("B0", PageSize.B0);
sizeMap.put("B1", PageSize.B1);
sizeMap.put("B2", PageSize.B2);
sizeMap.put("B3", PageSize.B3);
sizeMap.put("B4", PageSize.B4);
sizeMap.put("B5", PageSize.B5);
sizeMap.put("B6", PageSize.B6);
sizeMap.put("B7", PageSize.B7);
sizeMap.put("B8", PageSize.B8);
sizeMap.put("B9", PageSize.B9);
// Add other sizes
sizeMap.put("LETTER", PageSize.LETTER);
sizeMap.put("TABLOID", PageSize.TABLOID);
sizeMap.put("LEDGER", PageSize.LEDGER);
sizeMap.put("LEGAL", PageSize.LEGAL);
sizeMap.put("EXECUTIVE", PageSize.EXECUTIVE);
if (!sizeMap.containsKey(targetPageSize)) {
throw new IllegalArgumentException(
"Invalid pageSize. It must be one of the following: A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10");
}
PageSize pageSize = sizeMap.get(targetPageSize);
byte[] bytes = file.getBytes();
PdfReader reader = new PdfReader(new ByteArrayInputStream(bytes));
PdfDocument pdfDoc = new PdfDocument(reader);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = new PdfWriter(baos);
PdfDocument outputPdf = new PdfDocument(writer);
int totalPages = pdfDoc.getNumberOfPages();
for (int i = 1; i <= totalPages; i++) {
PdfPage page = outputPdf.addNewPage(pageSize);
PdfCanvas pdfCanvas = new PdfCanvas(page);
// Get the page and calculate scaling factors
Rectangle rect = pdfDoc.getPage(i).getPageSize();
float scaleWidth = pageSize.getWidth() / rect.getWidth();
float scaleHeight = pageSize.getHeight() / rect.getHeight();
float scale = Math.min(scaleWidth, scaleHeight) * scaleFactor;
System.out.println("Scale: " + scale);
PdfFormXObject formXObject = pdfDoc.getPage(i).copyAsFormXObject(outputPdf);
float x = (pageSize.getWidth() - rect.getWidth() * scale) / 2; // Center Page
float y = (pageSize.getHeight() - rect.getHeight() * scale) / 2;
// Save the graphics state, apply the transformations, add the object, and then
// restore the graphics state
pdfCanvas.saveState();
pdfCanvas.concatMatrix(scale, 0, 0, scale, x, y);
pdfCanvas.addXObject(formXObject, 0, 0);
pdfCanvas.restoreState();
}
outputPdf.close();
byte[] pdfContent = baos.toByteArray();
pdfDoc.close();
return WebResponseUtils.bytesToWebResponse(pdfContent,
file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_scaled.pdf");
}
//TODO
@Hidden
@PostMapping(value = "/auto-crop", consumes = "multipart/form-data")
public ResponseEntity<byte[]> cropPdf(@RequestParam("fileInput") MultipartFile file) throws IOException {
byte[] bytes = file.getBytes();
PdfReader reader = new PdfReader(new ByteArrayInputStream(bytes));
PdfDocument pdfDoc = new PdfDocument(reader);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = new PdfWriter(baos);
PdfDocument outputPdf = new PdfDocument(writer);
int totalPages = pdfDoc.getNumberOfPages();
for (int i = 1; i <= totalPages; i++) {
PdfPage page = pdfDoc.getPage(i);
Rectangle originalMediaBox = page.getMediaBox();
Rectangle contentBox = determineContentBox(page);
// Make sure we don't go outside the original media box.
Rectangle intersection = originalMediaBox.getIntersection(contentBox);
page.setCropBox(intersection);
// Copy page to the new document
outputPdf.addPage(page.copyTo(outputPdf));
}
outputPdf.close();
byte[] pdfContent = baos.toByteArray();
pdfDoc.close();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""
+ file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_cropped.pdf\"")
.contentType(MediaType.APPLICATION_PDF).body(pdfContent);
}
private Rectangle determineContentBox(PdfPage page) {
// Extract the text from the page and find the bounding box.
TextBoundingRectangleFinder finder = new TextBoundingRectangleFinder();
PdfCanvasProcessor processor = new PdfCanvasProcessor(finder);
processor.processPageContent(page);
return finder.getBoundingBox();
}
private static class TextBoundingRectangleFinder implements IEventListener {
private List<Rectangle> allTextBoxes = new ArrayList<>();
public Rectangle getBoundingBox() {
// Sort the text boxes based on their vertical position
allTextBoxes.sort(Comparator.comparingDouble(Rectangle::getTop));
// Consider a box an outlier if its top is more than 1.5 times the IQR above the
// third quartile.
int q1Index = allTextBoxes.size() / 4;
int q3Index = 3 * allTextBoxes.size() / 4;
double iqr = allTextBoxes.get(q3Index).getTop() - allTextBoxes.get(q1Index).getTop();
double threshold = allTextBoxes.get(q3Index).getTop() + 1.5 * iqr;
// Initialize boundingBox to the first non-outlier box
int i = 0;
while (i < allTextBoxes.size() && allTextBoxes.get(i).getTop() > threshold) {
i++;
}
if (i == allTextBoxes.size()) {
// If all boxes are outliers, just return the first one
return allTextBoxes.get(0);
}
Rectangle boundingBox = allTextBoxes.get(i);
// Extend the bounding box to include all non-outlier boxes
for (; i < allTextBoxes.size(); i++) {
Rectangle textBoundingBox = allTextBoxes.get(i);
if (textBoundingBox.getTop() > threshold) {
// This box is an outlier, skip it
continue;
}
float left = Math.min(boundingBox.getLeft(), textBoundingBox.getLeft());
float bottom = Math.min(boundingBox.getBottom(), textBoundingBox.getBottom());
float right = Math.max(boundingBox.getRight(), textBoundingBox.getRight());
float top = Math.max(boundingBox.getTop(), textBoundingBox.getTop());
// Add a small padding around the bounding box
float padding = 10;
boundingBox = new Rectangle(left - padding, bottom - padding, right - left + 2 * padding,
top - bottom + 2 * padding);
}
return boundingBox;
}
@Override
public void eventOccurred(IEventData data, EventType type) {
if (type == EventType.RENDER_TEXT) {
TextRenderInfo renderInfo = (TextRenderInfo) data;
allTextBoxes.add(renderInfo.getBaseline().getBoundingRectangle());
}
}
@Override
public Set<EventType> getSupportedEvents() {
return Collections.singleton(EventType.RENDER_TEXT);
}
}
}

View File

@@ -6,7 +6,6 @@ import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
@@ -16,9 +15,6 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
@@ -29,16 +25,20 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "General", description = "General APIs")
public class SplitPDFController {
private static final Logger logger = LoggerFactory.getLogger(SplitPDFController.class);
@PostMapping(consumes = "multipart/form-data", value = "/split-pages")
@Operation(summary = "Split a PDF file into separate documents",
description = "This endpoint splits a given PDF file into separate documents based on the specified page numbers or ranges. Users can specify pages using individual numbers, ranges, or 'all' for every page.")
public ResponseEntity<Resource> splitPdf(
description = "This endpoint splits a given PDF file into separate documents based on the specified page numbers or ranges. Users can specify pages using individual numbers, ranges, or 'all' for every page. Input:PDF Output:PDF Type:SIMO")
public ResponseEntity<byte[]> splitPdf(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to be split")
MultipartFile file,
@@ -58,39 +58,28 @@ public class SplitPDFController {
pageNumbers.add(i);
}
} else {
List<String> pageNumbersStr = new ArrayList<>(Arrays.asList(pages.split(",")));
if (!pageNumbersStr.contains(String.valueOf(document.getNumberOfPages()))) {
String lastpage = String.valueOf(document.getNumberOfPages());
pageNumbersStr.add(lastpage);
}
for (String page : pageNumbersStr) {
if (page.contains("-")) {
String[] range = page.split("-");
int start = Integer.parseInt(range[0]);
int end = Integer.parseInt(range[1]);
for (int i = start; i <= end; i++) {
pageNumbers.add(i);
}
} else {
pageNumbers.add(Integer.parseInt(page));
}
String[] splitPoints = pages.split(",");
for (String splitPoint : splitPoints) {
List<Integer> orderedPages = GeneralUtils.parsePageList(new String[] {splitPoint}, document.getNumberOfPages());
pageNumbers.addAll(orderedPages);
}
// Add the last page as a split point
pageNumbers.add(document.getNumberOfPages() - 1);
}
logger.info("Splitting PDF into pages: {}", pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
// split the document
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
int currentPage = 0;
for (int pageNumber : pageNumbers) {
int previousPageNumber = 0;
for (int splitPoint : pageNumbers) {
try (PDDocument splitDocument = new PDDocument()) {
for (int i = currentPage; i < pageNumber; i++) {
for (int i = previousPageNumber; i <= splitPoint; i++) {
PDPage page = document.getPage(i);
splitDocument.addPage(page);
logger.debug("Adding page {} to split document", i);
}
currentPage = pageNumber;
logger.debug("Setting current page to {}", currentPage);
previousPageNumber = splitPoint + 1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
splitDocument.save(baos);
@@ -102,15 +91,17 @@ public class SplitPDFController {
}
}
// closing the original document
document.close();
Path zipFile = Files.createTempFile("split_documents", ".zip");
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
// loop through the split documents and write them to the zip file
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
String fileName = "split_document_" + (i + 1) + ".pdf";
String fileName = filename + "_" + (i + 1) + ".pdf";
ByteArrayOutputStream baos = splitDocumentsBoas.get(i);
byte[] pdf = baos.toByteArray();
@@ -129,12 +120,11 @@ public class SplitPDFController {
logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
byte[] data = Files.readAllBytes(zipFile);
ByteArrayResource resource = new ByteArrayResource(data);
Files.delete(zipFile);
// return the Resource in the response
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_split.zip")
.contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength()).body(resource);
return WebResponseUtils.bytesToWebResponse(data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
}
}

View File

@@ -20,15 +20,18 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Convert", description = "Convert APIs")
public class ConvertImgPDFController {
private static final Logger logger = LoggerFactory.getLogger(ConvertImgPDFController.class);
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-img")
@Operation(summary = "Convert PDF to image(s)",
description = "This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images.")
description = "This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images. Input:PDF Output:Image Type:SI-Conditional")
public ResponseEntity<Resource> convertToImage(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to be converted")
@@ -56,8 +59,9 @@ public class ConvertImgPDFController {
// returns bytes for image
boolean singleImage = singleOrMultiple.equals("single");
byte[] result = null;
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
try {
result = PdfUtils.convertFromPdf(pdfBytes, imageFormat.toUpperCase(), colorTypeResult, singleImage, Integer.valueOf(dpi));
result = PdfUtils.convertFromPdf(pdfBytes, imageFormat.toUpperCase(), colorTypeResult, singleImage, Integer.valueOf(dpi), filename);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -74,14 +78,14 @@ public class ConvertImgPDFController {
ByteArrayResource resource = new ByteArrayResource(result);
// return the Resource in the response
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToImages.zip")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename + "_convertedToImages.zip")
.contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength()).body(resource);
}
}
@PostMapping(consumes = "multipart/form-data", value = "/img-to-pdf")
@Operation(summary = "Convert images to a PDF file",
description = "This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images.")
description = "This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images. Input:Image Output:PDF Type:SISO?")
public ResponseEntity<byte[]> convertToPdf(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input images to be converted to a PDF file")
@@ -97,7 +101,7 @@ public class ConvertImgPDFController {
boolean autoRotate) throws IOException {
// Convert the file to PDF and get the resulting bytes
byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate, colorType);
return PdfUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_coverted.pdf");
return WebResponseUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_converted.pdf");
}
private String getMediaType(String imageFormat) {

View File

@@ -17,10 +17,12 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Convert", description = "Convert APIs")
public class ConvertOfficeController {
public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
@@ -57,8 +59,8 @@ public class ConvertOfficeController {
@PostMapping(consumes = "multipart/form-data", value = "/file-to-pdf")
@Operation(
summary = "Convert a file to a PDF using OCR",
description = "This endpoint converts a given file to a PDF using Optical Character Recognition (OCR). The filename of the resulting PDF will be the original filename with '_convertedToPDF.pdf' appended."
summary = "Convert a file to a PDF using LibreOffice",
description = "This endpoint converts a given file to a PDF using LibreOffice API Input:Any Output:PDF Type:SISO"
)
public ResponseEntity<byte[]> processPdfWithOCR(
@RequestPart(required = true, value = "fileInput")
@@ -72,7 +74,7 @@ public class ConvertOfficeController {
// LibreOfficeListener.getInstance().start();
byte[] pdfByteArray = convertToPdf(inputFile);
return PdfUtils.bytesToWebResponse(pdfByteArray, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
return WebResponseUtils.bytesToWebResponse(pdfByteArray, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
}
}

View File

@@ -12,13 +12,15 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.PDFToFile;
@RestController
@Tag(name = "Convert", description = "Convert APIs")
public class ConvertPDFToOffice {
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-html")
@Operation(summary = "Convert PDF to HTML", description = "This endpoint converts a PDF file to HTML format.")
@Operation(summary = "Convert PDF to HTML", description = "This endpoint converts a PDF file to HTML format. Input:PDF Output:HTML Type:SISO")
public ResponseEntity<byte[]> processPdfToHTML(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to HTML format", required = true) MultipartFile inputFile)
throws IOException, InterruptedException {
@@ -27,7 +29,7 @@ public class ConvertPDFToOffice {
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-presentation")
@Operation(summary = "Convert PDF to Presentation format", description = "This endpoint converts a given PDF file to a Presentation format.")
@Operation(summary = "Convert PDF to Presentation format", description = "This endpoint converts a given PDF file to a Presentation format. Input:PDF Output:PPT Type:SISO")
public ResponseEntity<byte[]> processPdfToPresentation(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file") MultipartFile inputFile,
@RequestParam("outputFormat") @Parameter(description = "The output Presentation format", schema = @Schema(allowableValues = {
@@ -38,7 +40,7 @@ public class ConvertPDFToOffice {
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-text")
@Operation(summary = "Convert PDF to Text or RTF format", description = "This endpoint converts a given PDF file to Text or RTF format.")
@Operation(summary = "Convert PDF to Text or RTF format", description = "This endpoint converts a given PDF file to Text or RTF format. Input:PDF Output:TXT Type:SISO")
public ResponseEntity<byte[]> processPdfToRTForTXT(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file") MultipartFile inputFile,
@RequestParam("outputFormat") @Parameter(description = "The output Text or RTF format", schema = @Schema(allowableValues = {
@@ -49,7 +51,7 @@ public class ConvertPDFToOffice {
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-word")
@Operation(summary = "Convert PDF to Word document", description = "This endpoint converts a given PDF file to a Word document format.")
@Operation(summary = "Convert PDF to Word document", description = "This endpoint converts a given PDF file to a Word document format. Input:PDF Output:WORD Type:SISO")
public ResponseEntity<byte[]> processPdfToWord(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file") MultipartFile inputFile,
@RequestParam("outputFormat") @Parameter(description = "The output Word document format", schema = @Schema(allowableValues = {
@@ -60,7 +62,7 @@ public class ConvertPDFToOffice {
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-xml")
@Operation(summary = "Convert PDF to XML", description = "This endpoint converts a PDF file to an XML file.")
@Operation(summary = "Convert PDF to XML", description = "This endpoint converts a PDF file to an XML file. Input:PDF Output:XML Type:SISO")
public ResponseEntity<byte[]> processPdfToXML(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to an XML file", required = true) MultipartFile inputFile)
throws IOException, InterruptedException {

View File

@@ -14,16 +14,18 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Convert", description = "Convert APIs")
public class ConvertPDFToPDFA {
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-pdfa")
@Operation(
summary = "Convert a PDF to a PDF/A",
description = "This endpoint converts a PDF file to a PDF/A file. PDF/A is a format designed for long-term archiving of digital documents."
description = "This endpoint converts a PDF file to a PDF/A file. PDF/A is a format designed for long-term archiving of digital documents. Input:PDF Output:PDF Type:SISO"
)
public ResponseEntity<byte[]> pdfToPdfA(
@RequestPart(required = true, value = "fileInput")
@@ -58,7 +60,7 @@ public class ConvertPDFToPDFA {
// Return the optimized PDF as a response
String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_PDFA.pdf";
return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
}
}

View File

@@ -0,0 +1,162 @@
package stirling.software.SPDF.controller.api.filters;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Filter", description = "Filter APIs")
public class FilterController {
@PostMapping(consumes = "multipart/form-data", value = "/contains-text")
@Operation(summary = "Checks if a PDF contains set text, returns true if does", description = "Input:PDF Output:Boolean Type:SISO")
public Boolean containsText(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
@Parameter(description = "The text to check for", required = true) String text,
@Parameter(description = "The page number to check for text on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
throws IOException, InterruptedException {
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
return PdfUtils.hasText(pdfDocument, pageNumber);
}
@PostMapping(consumes = "multipart/form-data", value = "/contains-image")
@Operation(summary = "Checks if a PDF contains an image", description = "Input:PDF Output:Boolean Type:SISO")
public Boolean containsImage(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
@Parameter(description = "The page number to check for image on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
throws IOException, InterruptedException {
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
return PdfUtils.hasImagesOnPage(null);
}
@PostMapping(consumes = "multipart/form-data", value = "/page-count")
@Operation(summary = "Checks if a PDF is greater, less or equal to a setPageCount", description = "Input:PDF Output:Boolean Type:SISO")
public Boolean pageCount(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
@Parameter(description = "Page Count", required = true) String pageCount,
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
throws IOException, InterruptedException {
// Load the PDF
PDDocument document = PDDocument.load(inputFile.getInputStream());
int actualPageCount = document.getNumberOfPages();
// Perform the comparison
switch (comparator) {
case "Greater":
return actualPageCount > Integer.parseInt(pageCount);
case "Equal":
return actualPageCount == Integer.parseInt(pageCount);
case "Less":
return actualPageCount < Integer.parseInt(pageCount);
default:
throw new IllegalArgumentException("Invalid comparator: " + comparator);
}
}
@PostMapping(consumes = "multipart/form-data", value = "/page-size")
@Operation(summary = "Checks if a PDF is of a certain size", description = "Input:PDF Output:Boolean Type:SISO")
public Boolean pageSize(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
@Parameter(description = "Standard Page Size", required = true) String standardPageSize,
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
throws IOException, InterruptedException {
// Load the PDF
PDDocument document = PDDocument.load(inputFile.getInputStream());
PDPage firstPage = document.getPage(0);
PDRectangle actualPageSize = firstPage.getMediaBox();
// Calculate the area of the actual page size
float actualArea = actualPageSize.getWidth() * actualPageSize.getHeight();
// Get the standard size and calculate its area
PDRectangle standardSize = PdfUtils.textToPageSize(standardPageSize);
float standardArea = standardSize.getWidth() * standardSize.getHeight();
// Perform the comparison
switch (comparator) {
case "Greater":
return actualArea > standardArea;
case "Equal":
return actualArea == standardArea;
case "Less":
return actualArea < standardArea;
default:
throw new IllegalArgumentException("Invalid comparator: " + comparator);
}
}
@PostMapping(consumes = "multipart/form-data", value = "/file-size")
@Operation(summary = "Checks if a PDF is a set file size", description = "Input:PDF Output:Boolean Type:SISO")
public Boolean fileSize(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
@Parameter(description = "File Size", required = true) String fileSize,
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
throws IOException, InterruptedException {
// Get the file size
long actualFileSize = inputFile.getSize();
// Perform the comparison
switch (comparator) {
case "Greater":
return actualFileSize > Long.parseLong(fileSize);
case "Equal":
return actualFileSize == Long.parseLong(fileSize);
case "Less":
return actualFileSize < Long.parseLong(fileSize);
default:
throw new IllegalArgumentException("Invalid comparator: " + comparator);
}
}
@PostMapping(consumes = "multipart/form-data", value = "/page-rotation")
@Operation(summary = "Checks if a PDF is of a certain rotation", description = "Input:PDF Output:Boolean Type:SISO")
public Boolean pageRotation(
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
@Parameter(description = "Rotation in degrees", required = true) int rotation,
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
throws IOException, InterruptedException {
// Load the PDF
PDDocument document = PDDocument.load(inputFile.getInputStream());
// Get the rotation of the first page
PDPage firstPage = document.getPage(0);
int actualRotation = firstPage.getRotation();
// Perform the comparison
switch (comparator) {
case "Greater":
return actualRotation > rotation;
case "Equal":
return actualRotation == rotation;
case "Less":
return actualRotation < rotation;
default:
throw new IllegalArgumentException("Invalid comparator: " + comparator);
}
}
}

View File

@@ -28,17 +28,19 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.ImageFinder;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class BlankPageController {
@PostMapping(consumes = "multipart/form-data", value = "/remove-blanks")
@Operation(
summary = "Remove blank pages from a PDF file",
description = "This endpoint removes blank pages from a given PDF file. Users can specify the threshold and white percentage to tune the detection of blank pages."
description = "This endpoint removes blank pages from a given PDF file. Users can specify the threshold and white percentage to tune the detection of blank pages. Input:PDF Output:PDF Type:SISO"
)
public ResponseEntity<byte[]> removeBlankPages(
@RequestPart(required = true, value = "fileInput")
@@ -71,7 +73,7 @@ public class BlankPageController {
pagesToKeepIndex.add(pageIndex);
System.out.println("page " + pageIndex + " has text");
} else {
boolean hasImages = hasImagesOnPage(page);
boolean hasImages = PdfUtils.hasImagesOnPage(page);
if (hasImages) {
System.out.println("page " + pageIndex + " has image");
@@ -109,7 +111,7 @@ public class BlankPageController {
}
}
return PdfUtils.pdfDocToWebResponse(document, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_blanksRemoved.pdf");
return WebResponseUtils.pdfDocToWebResponse(document, inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_blanksRemoved.pdf");
} catch (IOException e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
@@ -120,9 +122,5 @@ public class BlankPageController {
}
private static boolean hasImagesOnPage(PDPage page) throws IOException {
ImageFinder imageFinder = new ImageFinder(page);
imageFinder.processPage(page);
return imageFinder.hasImages();
}
}

View File

@@ -31,16 +31,19 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class CompressController {
private static final Logger logger = LoggerFactory.getLogger(CompressController.class);
@PostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
@Operation(summary = "Optimize PDF file", description = "This endpoint accepts a PDF file and optimizes it based on the provided parameters.")
@Operation(summary = "Optimize PDF file", description = "This endpoint accepts a PDF file and optimizes it based on the provided parameters. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> optimizePdf(
@RequestPart(value = "fileInput") @Parameter(description = "The input PDF file to be optimized.", required = true) MultipartFile inputFile,
@RequestParam(required = false, value = "optimizeLevel") @Parameter(description = "The level of optimization to apply to the PDF file. Higher values indicate greater compression but may reduce quality.", schema = @Schema(allowableValues = {
@@ -55,7 +58,7 @@ public class CompressController {
Long expectedOutputSize = 0L;
boolean autoMode = false;
if (expectedOutputSizeString != null && expectedOutputSizeString.length() > 1 ) {
expectedOutputSize = PdfUtils.convertSizeToBytes(expectedOutputSizeString);
expectedOutputSize = GeneralUtils.convertSizeToBytes(expectedOutputSizeString);
autoMode = true;
}
@@ -224,7 +227,7 @@ public class CompressController {
// Return the optimized PDF as a response
String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_Optimized.pdf";
return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
}
}

View File

@@ -31,17 +31,19 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class ExtractImageScansController {
private static final Logger logger = LoggerFactory.getLogger(ExtractImageScansController.class);
@PostMapping(consumes = "multipart/form-data", value = "/extract-image-scans")
@Operation(summary = "Extract image scans from an input file",
description = "This endpoint extracts image scans from a given file based on certain parameters. Users can specify angle threshold, tolerance, minimum area, minimum contour area, and border size.")
description = "This endpoint extracts image scans from a given file based on certain parameters. Users can specify angle threshold, tolerance, minimum area, minimum contour area, and border size. Input:PDF Output:IMAGE/ZIP Type:SIMO")
public ResponseEntity<byte[]> extractImageScans(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input file containing image scans")
@@ -147,11 +149,11 @@ public class ExtractImageScansController {
// Clean up the temporary zip file
Files.delete(tempZipFile);
return PdfUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
return WebResponseUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
} else {
// Return the processed image as a response
byte[] imageBytes = processedImageBytes.get(0);
return PdfUtils.bytesToWebResponse(imageBytes, fileName.replaceFirst("[.][^.]+$", "") + ".png", MediaType.IMAGE_PNG);
return WebResponseUtils.bytesToWebResponse(imageBytes, fileName.replaceFirst("[.][^.]+$", "") + ".png", MediaType.IMAGE_PNG);
}
}

View File

@@ -29,15 +29,17 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class ExtractImagesController {
private static final Logger logger = LoggerFactory.getLogger(ExtractImagesController.class);
@PostMapping(consumes = "multipart/form-data", value = "/extract-images")
@Operation(summary = "Extract images from a PDF file",
description = "This endpoint extracts images from a given PDF file and returns them in a zip file. Users can specify the output image format.")
description = "This endpoint extracts images from a given PDF file and returns them in a zip file. Users can specify the output image format. Input:PDF Output:IMAGE/ZIP Type:SIMO")
public ResponseEntity<byte[]> extractImages(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file containing images")
@@ -59,7 +61,7 @@ public class ExtractImagesController {
zos.setLevel(Deflater.BEST_COMPRESSION);
int imageIndex = 1;
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
int pageNum = 1;
// Iterate over each page
for (PDPage page : document.getPages()) {
@@ -81,7 +83,7 @@ public class ExtractImagesController {
}
// Write image to zip file
String imageName = "Image " + imageIndex + " (Page " + pageNum + ")." + format;
String imageName = filename + "_" + imageIndex + " (Page " + pageNum + ")." + format;
ZipEntry zipEntry = new ZipEntry(imageName);
zos.putNextEntry(zipEntry);
@@ -106,7 +108,7 @@ public class ExtractImagesController {
// Create ByteArrayResource from byte array
byte[] zipContents = baos.toByteArray();
return PdfUtils.boasToWebResponse(baos, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_extracted-images.zip", MediaType.APPLICATION_OCTET_STREAM);
return WebResponseUtils.boasToWebResponse(baos, filename + "_extracted-images.zip", MediaType.APPLICATION_OCTET_STREAM);
}
}

View File

@@ -0,0 +1,151 @@
package stirling.software.SPDF.controller.api.other;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
//Required for image manipulation
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.RescaleOp;
//Required for file input/output
import java.io.File;
import java.io.IOException;
//Other required classes
import java.util.Random;
//Required for image input/output
import javax.imageio.ImageIO;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.itextpdf.io.source.ByteArrayOutputStream;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class FakeScanControllerWIP {
private static final Logger logger = LoggerFactory.getLogger(FakeScanControllerWIP.class);
//TODO
@Hidden
@PostMapping(consumes = "multipart/form-data", value = "/fakeScan")
@Operation(
summary = "Repair a PDF file",
description = "This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response."
)
public ResponseEntity<byte[]> repairPdf(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to be repaired", required = true)
MultipartFile inputFile) throws IOException, InterruptedException {
PDDocument document = PDDocument.load(inputFile.getBytes());
PDFRenderer pdfRenderer = new PDFRenderer(document);
for (int page = 0; page < document.getNumberOfPages(); ++page)
{
BufferedImage image = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
ImageIO.write(image, "png", new File("scanned-" + (page+1) + ".png"));
}
document.close();
// Constants
int scannedness = 90; // Value between 0 and 100
int dirtiness = 0; // Value between 0 and 100
// Load the source image
BufferedImage sourceImage = ImageIO.read(new File("scanned-1.png"));
// Create the destination image
BufferedImage destinationImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), sourceImage.getType());
// Apply a brightness and contrast effect based on the "scanned-ness"
float scaleFactor = 1.0f + (scannedness / 100.0f) * 0.5f; // Between 1.0 and 1.5
float offset = scannedness * 1.5f; // Between 0 and 150
BufferedImageOp op = new RescaleOp(scaleFactor, offset, null);
op.filter(sourceImage, destinationImage);
// Apply a rotation effect
double rotationRequired = Math.toRadians((new Random().nextInt(3 - 1) + 1)); // Random angle between 1 and 3 degrees
double locationX = destinationImage.getWidth() / 2;
double locationY = destinationImage.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp rotateOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
destinationImage = rotateOp.filter(destinationImage, null);
// Apply a blur effect based on the "scanned-ness"
float blurIntensity = scannedness / 100.0f * 0.2f; // Between 0.0 and 0.2
float[] matrix = {
blurIntensity, blurIntensity, blurIntensity,
blurIntensity, blurIntensity, blurIntensity,
blurIntensity, blurIntensity, blurIntensity
};
BufferedImageOp blurOp = new ConvolveOp(new Kernel(3, 3, matrix), ConvolveOp.EDGE_NO_OP, null);
destinationImage = blurOp.filter(destinationImage, null);
// Add noise to the image based on the "dirtiness"
Random random = new Random();
for (int y = 0; y < destinationImage.getHeight(); y++) {
for (int x = 0; x < destinationImage.getWidth(); x++) {
if (random.nextInt(100) < dirtiness) {
// Change the pixel color to black randomly based on the "dirtiness"
destinationImage.setRGB(x, y, Color.BLACK.getRGB());
}
}
}
// Save the image
ImageIO.write(destinationImage, "PNG", new File("scanned-1.png"));
PDDocument documentOut = new PDDocument();
for (int page = 1; page <= document.getNumberOfPages(); ++page)
{
BufferedImage bim = ImageIO.read(new File("scanned-" + page + ".png"));
// Adjust the dimensions of the page
PDPage pdPage = new PDPage(new PDRectangle(bim.getWidth() - 1, bim.getHeight() - 1));
documentOut.addPage(pdPage);
PDImageXObject pdImage = LosslessFactory.createFromImage(documentOut, bim);
PDPageContentStream contentStream = new PDPageContentStream(documentOut, pdPage);
// Draw the image with a slight offset and enlarged dimensions
contentStream.drawImage(pdImage, -1, -1, bim.getWidth() + 2, bim.getHeight() + 2);
contentStream.close();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
documentOut.save(baos);
documentOut.close();
// Return the optimized PDF as a response
String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_scanned.pdf";
return WebResponseUtils.boasToWebResponse(baos, outputFilename);
}
}

View File

@@ -19,9 +19,11 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class MetadataController {
@@ -38,7 +40,7 @@ public class MetadataController {
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
@Operation(summary = "Update metadata of a PDF file",
description = "This endpoint allows you to update the metadata of a given PDF file. You can add, modify, or delete standard and custom metadata fields.")
description = "This endpoint allows you to update the metadata of a given PDF file. You can add, modify, or delete standard and custom metadata fields. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> metadata(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to update metadata")
@@ -73,6 +75,7 @@ public class MetadataController {
@RequestParam(value = "trapped", required = false)
@Parameter(description = "The trapped status of the document")
String trapped,
@Parameter(description = "Map list of key and value of custom parameters, note these must start with customKey and customValue if they are non standard")
@RequestParam Map<String, String> allRequestParams)
throws IOException {
@@ -159,7 +162,7 @@ public class MetadataController {
info.setTrapped(trapped);
document.setDocumentInformation(info);
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf");
return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf");
}
}

View File

@@ -27,10 +27,12 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class OCRController {
private static final Logger logger = LoggerFactory.getLogger(OCRController.class);
@@ -47,7 +49,7 @@ public class OCRController {
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
@Operation(summary = "Process a PDF file with OCR",
description = "This endpoint processes a PDF file using OCR (Optical Character Recognition). Users can specify languages, sidecar, deskew, clean, cleanFinal, ocrType, ocrRenderType, and removeImagesAfter options.")
description = "This endpoint processes a PDF file using OCR (Optical Character Recognition). Users can specify languages, sidecar, deskew, clean, cleanFinal, ocrType, ocrRenderType, and removeImagesAfter options. Input:PDF Output:PDF Type:SI-Conditional")
public ResponseEntity<byte[]> processPdfWithOCR(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to be processed with OCR")
@@ -189,11 +191,11 @@ public class OCRController {
Files.delete(sidecarTextPath);
// Return the zip file containing both the PDF and the text file
return PdfUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
return WebResponseUtils.bytesToWebResponse(zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
} else {
// Return the OCR processed PDF as a response
Files.delete(tempOutputFile);
return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
}
}

View File

@@ -14,9 +14,12 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class OverlayImageController {
private static final Logger logger = LoggerFactory.getLogger(OverlayImageController.class);
@@ -24,7 +27,7 @@ public class OverlayImageController {
@PostMapping(consumes = "multipart/form-data", value = "/add-image")
@Operation(
summary = "Overlay image onto a PDF file",
description = "This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified."
description = "This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified. Input:PDF/IMAGE Output:PDF Type:MF-SISO"
)
public ResponseEntity<byte[]> overlayImage(
@RequestPart(required = true, value = "fileInput")
@@ -47,7 +50,7 @@ public class OverlayImageController {
byte[] imageBytes = imageFile.getBytes();
byte[] result = PdfUtils.overlayImage(pdfBytes, imageBytes, x, y, everyPage);
return PdfUtils.bytesToWebResponse(result, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
return WebResponseUtils.bytesToWebResponse(result, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
} catch (IOException e) {
logger.error("Failed to add image to PDF", e);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);

View File

@@ -16,10 +16,12 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Other", description = "Other APIs")
public class RepairController {
private static final Logger logger = LoggerFactory.getLogger(RepairController.class);
@@ -27,7 +29,7 @@ public class RepairController {
@PostMapping(consumes = "multipart/form-data", value = "/repair")
@Operation(
summary = "Repair a PDF file",
description = "This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response."
description = "This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response. Input:PDF Output:PDF Type:SISO"
)
public ResponseEntity<byte[]> repairPdf(
@RequestPart(required = true, value = "fileInput")
@@ -60,7 +62,7 @@ public class RepairController {
// Return the optimized PDF as a response
String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_repaired.pdf";
return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
}
}

View File

@@ -0,0 +1,399 @@
package stirling.software.SPDF.controller.api.pipeline;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.PipelineConfig;
import stirling.software.SPDF.model.PipelineOperation;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Pipeline", description = "Pipeline APIs")
public class Controller {
@Autowired
private ObjectMapper objectMapper;
final String jsonFileName = "pipelineCofig.json";
final String watchedFoldersDir = "watchedFolders/";
@Scheduled(fixedRate = 5000)
public void scanFolders() {
Path watchedFolderPath = Paths.get(watchedFoldersDir);
if (!Files.exists(watchedFolderPath)) {
try {
Files.createDirectories(watchedFolderPath);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
try (Stream<Path> paths = Files.walk(watchedFolderPath)) {
paths.filter(Files::isDirectory).forEach(t -> {
try {
if (!t.equals(watchedFolderPath) && !t.endsWith("processing")) {
handleDirectory(t);
}
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
private void handleDirectory(Path dir) throws Exception {
Path jsonFile = dir.resolve(jsonFileName);
Path processingDir = dir.resolve("processing"); // Directory to move files during processing
if (!Files.exists(processingDir)) {
Files.createDirectory(processingDir);
}
if (Files.exists(jsonFile)) {
// Read JSON file
String jsonString;
try {
jsonString = new String(Files.readAllBytes(jsonFile));
} catch (IOException e) {
e.printStackTrace();
return;
}
// Decode JSON to PipelineConfig
PipelineConfig config;
try {
config = objectMapper.readValue(jsonString, PipelineConfig.class);
// Assuming your PipelineConfig class has getters for all necessary fields, you can perform checks here
if (config.getOperations() == null || config.getOutputDir() == null || config.getName() == null) {
throw new IOException("Invalid JSON format");
}
} catch (IOException e) {
e.printStackTrace();
return;
}
// For each operation in the pipeline
for (PipelineOperation operation : config.getOperations()) {
// Collect all files based on fileInput
File[] files;
String fileInput = (String) operation.getParameters().get("fileInput");
if ("automated".equals(fileInput)) {
// If fileInput is "automated", process all files in the directory
try (Stream<Path> paths = Files.list(dir)) {
files = paths.filter(path -> !path.equals(jsonFile))
.map(Path::toFile)
.toArray(File[]::new);
} catch (IOException e) {
e.printStackTrace();
return;
}
} else {
// If fileInput contains a path, process only this file
files = new File[]{new File(fileInput)};
}
// Prepare the files for processing
File[] filesToProcess = files.clone();
for (File file : filesToProcess) {
Files.move(file.toPath(), processingDir.resolve(file.getName()));
}
// Process the files
try {
List<Resource> resources = handleFiles(filesToProcess, jsonString);
// Move resultant files and rename them as per config in JSON file
for (Resource resource : resources) {
String outputFileName = config.getOutputPattern().replace("{filename}", resource.getFile().getName());
outputFileName = outputFileName.replace("{pipelineName}", config.getName());
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
outputFileName = outputFileName.replace("{date}", LocalDate.now().format(dateFormatter));
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HHmmss");
outputFileName = outputFileName.replace("{time}", LocalTime.now().format(timeFormatter));
// {filename} {folder} {date} {tmime} {pipeline}
Files.move(resource.getFile().toPath(), Paths.get(config.getOutputDir(), outputFileName));
}
// If successful, delete the original files
for (File file : filesToProcess) {
Files.deleteIfExists(processingDir.resolve(file.getName()));
}
} catch (Exception e) {
// If an error occurs, move the original files back
for (File file : filesToProcess) {
Files.move(processingDir.resolve(file.getName()), file.toPath());
}
throw e;
}
}
}
}
List<Resource> processFiles(List<Resource> outputFiles, String jsonString) throws Exception{
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(jsonString);
JsonNode pipelineNode = jsonNode.get("pipeline");
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
PrintStream logPrintStream = new PrintStream(logStream);
boolean hasErrors = false;
for (JsonNode operationNode : pipelineNode) {
String operation = operationNode.get("operation").asText();
JsonNode parametersNode = operationNode.get("parameters");
String inputFileExtension = "";
if(operationNode.has("inputFileType")) {
inputFileExtension = operationNode.get("inputFileType").asText();
} else {
inputFileExtension=".pdf";
}
List<Resource> newOutputFiles = new ArrayList<>();
boolean hasInputFileType = false;
for (Resource file : outputFiles) {
if (file.getFilename().endsWith(inputFileExtension)) {
hasInputFileType = true;
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("fileInput", file);
Iterator<Map.Entry<String, JsonNode>> parameters = parametersNode.fields();
while (parameters.hasNext()) {
Map.Entry<String, JsonNode> parameter = parameters.next();
body.add(parameter.getKey(), parameter.getValue().asText());
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/" + operation;
ResponseEntity<byte[]> response = restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
if (!response.getStatusCode().equals(HttpStatus.OK)) {
logPrintStream.println("Error: " + response.getBody());
hasErrors = true;
continue;
}
// Check if the response body is a zip file
if (isZip(response.getBody())) {
// Unzip the file and add all the files to the new output files
newOutputFiles.addAll(unzip(response.getBody()));
} else {
Resource outputResource = new ByteArrayResource(response.getBody()) {
@Override
public String getFilename() {
return file.getFilename(); // Preserving original filename
}
};
newOutputFiles.add(outputResource);
}
}
if (!hasInputFileType) {
logPrintStream.println("No files with extension " + inputFileExtension + " found for operation " + operation);
hasErrors = true;
}
outputFiles = newOutputFiles;
}
logPrintStream.close();
}
return outputFiles;
}
List<Resource> handleFiles(File[] files, String jsonString) throws Exception{
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(jsonString);
JsonNode pipelineNode = jsonNode.get("pipeline");
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
PrintStream logPrintStream = new PrintStream(logStream);
boolean hasErrors = false;
List<Resource> outputFiles = new ArrayList<>();
for (File file : files) {
Path path = Paths.get(file.getAbsolutePath());
Resource fileResource = new ByteArrayResource(Files.readAllBytes(path)) {
@Override
public String getFilename() {
return file.getName();
}
};
outputFiles.add(fileResource);
}
return processFiles(outputFiles, jsonString);
}
List<Resource> handleFiles(MultipartFile[] files, String jsonString) throws Exception{
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(jsonString);
JsonNode pipelineNode = jsonNode.get("pipeline");
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
PrintStream logPrintStream = new PrintStream(logStream);
boolean hasErrors = false;
List<Resource> outputFiles = new ArrayList<>();
for (MultipartFile file : files) {
Resource fileResource = new ByteArrayResource(file.getBytes()) {
@Override
public String getFilename() {
return file.getOriginalFilename();
}
};
outputFiles.add(fileResource);
}
return processFiles(outputFiles, jsonString);
}
@PostMapping("/handleData")
public ResponseEntity<byte[]> handleData(@RequestPart("fileInput") MultipartFile[] files,
@RequestParam("json") String jsonString) {
try {
List<Resource> outputFiles = handleFiles(files, jsonString);
if (outputFiles.size() == 1) {
// If there is only one file, return it directly
Resource singleFile = outputFiles.get(0);
InputStream is = singleFile.getInputStream();
byte[] bytes = new byte[(int)singleFile.contentLength()];
is.read(bytes);
is.close();
return WebResponseUtils.bytesToWebResponse(bytes, singleFile.getFilename(), MediaType.APPLICATION_OCTET_STREAM);
}
// Create a ByteArrayOutputStream to hold the zip
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(baos);
// Loop through each file and add it to the zip
for (Resource file : outputFiles) {
ZipEntry zipEntry = new ZipEntry(file.getFilename());
zipOut.putNextEntry(zipEntry);
// Read the file into a byte array
InputStream is = file.getInputStream();
byte[] bytes = new byte[(int)file.contentLength()];
is.read(bytes);
// Write the bytes of the file to the zip
zipOut.write(bytes, 0, bytes.length);
zipOut.closeEntry();
is.close();
}
zipOut.close();
return WebResponseUtils.boasToWebResponse(baos, "output.zip", MediaType.APPLICATION_OCTET_STREAM);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private boolean isZip(byte[] data) {
if (data == null || data.length < 4) {
return false;
}
// Check the first four bytes of the data against the standard zip magic number
return data[0] == 0x50 && data[1] == 0x4B && data[2] == 0x03 && data[3] == 0x04;
}
private List<Resource> unzip(byte[] data) throws IOException {
List<Resource> unzippedFiles = new ArrayList<>();
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
ZipInputStream zis = new ZipInputStream(bais)) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
final String filename = entry.getName();
Resource fileResource = new ByteArrayResource(baos.toByteArray()) {
@Override
public String getFilename() {
return filename;
}
};
// If the unzipped file is a zip file, unzip it
if (isZip(baos.toByteArray())) {
unzippedFiles.addAll(unzip(baos.toByteArray()));
} else {
unzippedFiles.add(fileResource);
}
}
}
return unzippedFiles;
}
}

View File

@@ -1,7 +1,6 @@
package stirling.software.SPDF.controller.api.security;
import java.io.ByteArrayInputStream;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -51,8 +50,11 @@ import com.itextpdf.signatures.SignatureUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Security", description = "Security APIs")
public class CertSignController {
private static final Logger logger = LoggerFactory.getLogger(CertSignController.class);
@@ -63,7 +65,7 @@ public class CertSignController {
@PostMapping(consumes = "multipart/form-data", value = "/cert-sign")
@Operation(summary = "Sign PDF with a Digital Certificate",
description = "This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file.")
description = "This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:MF-SISO")
public ResponseEntity<byte[]> signPDF(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to be signed")
@@ -177,8 +179,17 @@ public class CertSignController {
String signingDate = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z").format(new Date());
// Prepare the text for the digital signature
String layer2Text = String.format("Digitally signed by: %s\nDate: %s\nReason: %s\nLocation: %s", name, signingDate, reason, location);
StringBuilder layer2TextBuilder = new StringBuilder(String.format("Digitally signed by: %s\nDate: %s",
name != null ? name : "Unknown", signingDate));
if (reason != null && !reason.isEmpty()) {
layer2TextBuilder.append("\nReason: ").append(reason);
}
if (location != null && !location.isEmpty()) {
layer2TextBuilder.append("\nLocation: ").append(location);
}
String layer2Text = layer2TextBuilder.toString();
// Get the PDF font and measure the width and height of the text block
PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD);
float textWidth = Arrays.stream(layer2Text.split("\n"))
@@ -206,12 +217,12 @@ public class CertSignController {
// Configure the appearance of the digital signature
appearance.setPageRect(rect)
.setContact(name)
.setPageNumber(pageNumber)
.setReason(reason)
.setLocation(location)
.setReuseAppearance(false)
.setLayer2Text(layer2Text);
.setContact(name != null ? name : "")
.setPageNumber(pageNumber)
.setReason(reason != null ? reason : "")
.setLocation(location != null ? location : "")
.setReuseAppearance(false)
.setLayer2Text(layer2Text.toString());
signer.setFieldName("sig");
} else {
@@ -230,7 +241,7 @@ public class CertSignController {
System.out.println("Signed PDF size: " + signedPdf.size());
System.out.println("PDF signed = " + isPdfSigned(signedPdf.toByteArray()));
return PdfUtils.bytesToWebResponse(signedPdf.toByteArray(), "example.pdf");
return WebResponseUtils.bytesToWebResponse(signedPdf.toByteArray(), "example.pdf");
}
public boolean isPdfSigned(byte[] pdfData) throws IOException {

View File

@@ -17,8 +17,10 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@Tag(name = "Security", description = "Security APIs")
public class PasswordController {
private static final Logger logger = LoggerFactory.getLogger(PasswordController.class);
@@ -27,7 +29,7 @@ public class PasswordController {
@PostMapping(consumes = "multipart/form-data", value = "/remove-password")
@Operation(
summary = "Remove password from a PDF file",
description = "This endpoint removes the password from a protected PDF file. Users need to provide the existing password."
description = "This endpoint removes the password from a protected PDF file. Users need to provide the existing password. Input:PDF Output:PDF Type:SISO"
)
public ResponseEntity<byte[]> removePassword(
@RequestPart(required = true, value = "fileInput")
@@ -38,20 +40,23 @@ public class PasswordController {
String password) throws IOException {
PDDocument document = PDDocument.load(fileInput.getBytes(), password);
document.setAllSecurityToBeRemoved(true);
return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_password_removed.pdf");
return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_password_removed.pdf");
}
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
@Operation(
summary = "Add password to a PDF file",
description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file."
description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file. Input:PDF Output:PDF"
)
public ResponseEntity<byte[]> addPassword(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to which the password should be added", required = true)
MultipartFile fileInput,
@RequestParam(defaultValue = "", name = "ownerPassword")
@Parameter(description = "The owner password to be added to the PDF file (Restricts what can be done with the document once it is opened)")
String ownerPassword,
@RequestParam(defaultValue = "", name = "password")
@Parameter(description = "The password to be added to the PDF file")
@Parameter(description = "The password to be added to the PDF file (Restricts the opening of the document itself.)")
String password,
@RequestParam(defaultValue = "128", name = "keyLength")
@Parameter(description = "The length of the encryption key", schema = @Schema(allowableValues = {"40", "128", "256"}))
@@ -84,7 +89,6 @@ public class PasswordController {
PDDocument document = PDDocument.load(fileInput.getBytes());
AccessPermission ap = new AccessPermission();
ap.setCanAssembleDocument(!canAssembleDocument);
ap.setCanExtractContent(!canExtractContent);
ap.setCanExtractForAccessibility(!canExtractForAccessibility);
@@ -93,14 +97,17 @@ public class PasswordController {
ap.setCanModifyAnnotations(!canModifyAnnotations);
ap.setCanPrint(!canPrint);
ap.setCanPrintFaithful(!canPrintFaithful);
StandardProtectionPolicy spp = new StandardProtectionPolicy(password, password, ap);
StandardProtectionPolicy spp = new StandardProtectionPolicy(ownerPassword, password, ap);
spp.setEncryptionKeyLength(keyLength);
spp.setPermissions(ap);
document.protect(spp);
return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
return WebResponseUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
}

View File

@@ -1,15 +1,23 @@
package stirling.software.SPDF.controller.api.security;
import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@@ -19,18 +27,26 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import stirling.software.SPDF.utils.PdfUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.WebResponseUtils;
import io.swagger.v3.oas.annotations.media.Schema;
@RestController
@Tag(name = "Security", description = "Security APIs")
public class WatermarkController {
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
@Operation(summary = "Add watermark to a PDF file",
description = "This endpoint adds a watermark to a given PDF file. Users can specify the watermark text, font size, rotation, opacity, width spacer, and height spacer.")
description = "This endpoint adds a watermark to a given PDF file. Users can specify the watermark text, font size, rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> addWatermark(
@RequestPart(required = true, value = "fileInput")
@Parameter(description = "The input PDF file to add a watermark")
MultipartFile pdfFile,
@RequestParam(defaultValue = "roman", name = "alphabet")
@Parameter(description = "The selected alphabet",
schema = @Schema(type = "string",
allowableValues = {"roman","arabic","japanese","korean","chinese"},
defaultValue = "roman"))
String alphabet,
@RequestParam("watermarkText")
@Parameter(description = "The watermark text to add to the PDF file")
String watermarkText,
@@ -48,11 +64,11 @@ public class WatermarkController {
int widthSpacer,
@RequestParam(defaultValue = "50", name = "heightSpacer")
@Parameter(description = "The height spacer between watermark texts", example = "50")
int heightSpacer) throws IOException {
int heightSpacer) throws IOException, Exception {
// Load the input PDF
PDDocument document = PDDocument.load(pdfFile.getInputStream());
String producer = document.getDocumentInformation().getProducer();
// Create a page in the document
for (PDPage page : document.getPages()) {
@@ -64,8 +80,40 @@ public class WatermarkController {
graphicsState.setNonStrokingAlphaConstant(opacity);
contentStream.setGraphicsStateParameters(graphicsState);
// Set font of watermark
PDFont font = PDType1Font.HELVETICA_BOLD;
String resourceDir = "";
PDFont font = PDType1Font.HELVETICA_BOLD;
switch (alphabet) {
case "arabic":
resourceDir = "static/fonts/NotoSansArabic-Regular.ttf";
break;
case "japanese":
resourceDir = "static/fonts/Meiryo.ttf";
break;
case "korean":
resourceDir = "static/fonts/malgun.ttf";
break;
case "chinese":
resourceDir = "static/fonts/SimSun.ttf";
break;
case "roman":
default:
resourceDir = "static/fonts/NotoSans-Regular.ttf";
break;
}
if(!resourceDir.equals("")) {
ClassPathResource classPathResource = new ClassPathResource(resourceDir);
String fileExtension = resourceDir.substring(resourceDir.lastIndexOf("."));
File tempFile = File.createTempFile("NotoSansFont", fileExtension);
try (InputStream is = classPathResource.getInputStream(); FileOutputStream os = new FileOutputStream(tempFile)) {
IOUtils.copy(is, os);
}
font = PDType0Font.load(document, tempFile);
tempFile.deleteOnExit();
}
contentStream.beginText();
contentStream.setFont(font, fontSize);
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
@@ -81,17 +129,25 @@ public class WatermarkController {
// Add the watermark text
for (int i = 0; i < watermarkRows; i++) {
for (int j = 0; j < watermarkCols; j++) {
contentStream.setTextMatrix(Matrix.getRotateInstance((float) Math.toRadians(rotation), j * watermarkWidth, i * watermarkHeight));
if(producer.contains("Google Docs")) {
//This fixes weird unknown google docs y axis rotation/flip issue
//TODO: Long term fix one day
//contentStream.setTextMatrix(1, 0, 0, -1, j * watermarkWidth, pageHeight - i * watermarkHeight);
Matrix matrix = new Matrix(1, 0, 0, -1, j * watermarkWidth, pageHeight - i * watermarkHeight);
contentStream.setTextMatrix(matrix);
} else {
contentStream.setTextMatrix(Matrix.getRotateInstance((float) Math.toRadians(rotation), j * watermarkWidth, i * watermarkHeight));
}
contentStream.showTextWithPositioning(new Object[] { watermarkText });
}
}
contentStream.endText();
// Close the content stream
contentStream.close();
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
return WebResponseUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
}
}

View File

@@ -6,8 +6,10 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag;
@Controller
@Tag(name = "Convert", description = "Convert APIs")
public class ConverterWebController {
@GetMapping("/img-to-pdf")

View File

@@ -1,27 +1,29 @@
package stirling.software.SPDF.controller.web;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag;
@Controller
@Tag(name = "General", description = "General APIs")
public class GeneralWebController {
@GetMapping("/pipeline")
@Hidden
public String pipelineForm(Model model) {
model.addAttribute("currentPage", "pipeline");
return "pipeline";
}
@GetMapping("/merge-pdfs")
@Hidden
public String mergePdfForm(Model model) {
model.addAttribute("currentPage", "merge-pdfs");
return "merge-pdfs";
}
@GetMapping("/about")
@Hidden
public String gameForm(Model model) {
model.addAttribute("currentPage", "about");
return "about";
}
@GetMapping("/multi-tool")
@Hidden
@@ -29,17 +31,7 @@ public class GeneralWebController {
model.addAttribute("currentPage", "multi-tool");
return "multi-tool";
}
@GetMapping("/")
public String home(Model model) {
model.addAttribute("currentPage", "home");
return "home";
}
@GetMapping("/home")
public String root(Model model) {
return "redirect:/";
}
@GetMapping("/remove-pages")
@Hidden
@@ -76,20 +68,4 @@ public class GeneralWebController {
return "sign";
}
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
@Hidden
public String getRobotsTxt() {
String allowGoogleVisibility = System.getProperty("ALLOW_GOOGLE_VISIBILITY");
if (allowGoogleVisibility == null)
allowGoogleVisibility = System.getenv("ALLOW_GOOGLE_VISIBILITY");
if (allowGoogleVisibility == null)
allowGoogleVisibility = "false";
if (Boolean.parseBoolean(allowGoogleVisibility)) {
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nAllow: /";
} else {
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
}
}
}

View File

@@ -0,0 +1,52 @@
package stirling.software.SPDF.controller.web;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import io.swagger.v3.oas.annotations.Hidden;
@Controller
public class HomeWebController {
@GetMapping("/about")
@Hidden
public String gameForm(Model model) {
model.addAttribute("currentPage", "about");
return "about";
}
@GetMapping("/")
public String home(Model model) {
model.addAttribute("currentPage", "home");
return "home";
}
@GetMapping("/home")
public String root(Model model) {
return "redirect:/";
}
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
@Hidden
public String getRobotsTxt() {
String allowGoogleVisibility = System.getProperty("ALLOW_GOOGLE_VISIBILITY");
if (allowGoogleVisibility == null)
allowGoogleVisibility = System.getenv("ALLOW_GOOGLE_VISIBILITY");
if (allowGoogleVisibility == null)
allowGoogleVisibility = "false";
if (Boolean.parseBoolean(allowGoogleVisibility)) {
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nAllow: /";
} else {
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
}
}
}

View File

@@ -12,9 +12,12 @@ import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@RestController
@RequestMapping("/api/v1")
@Tag(name = "API", description = "Info APIs")
public class MetricsController {
private final MeterRegistry meterRegistry;
@@ -36,17 +39,31 @@ public class MetricsController {
@GetMapping("/loads")
@Operation(summary = "GET request count",
description = "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.")
public Double getPageLoads(@RequestParam Optional<String> endpoint) {
public Double getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
try {
double count = 0.0;
double count = 0.0;
for (Meter meter : meterRegistry.getMeters()) {
if (meter.getId().getName().equals("http.requests")) {
String method = meter.getId().getTag("method");
if (method != null && method.equals("GET")) {
if (meter instanceof Counter) {
count += ((Counter) meter).count();
}
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
if(!endpoint.get().startsWith("/")) {
endpoint = Optional.of("/" + endpoint.get());
}
System.out.println("loads " + endpoint.get() + " vs " + meter.getId().getTag("uri"));
if(endpoint.get().equals(meter.getId().getTag("uri"))){
if (meter instanceof Counter) {
count += ((Counter) meter).count();
}
}
} else {
if (meter instanceof Counter) {
count += ((Counter) meter).count();
}
}
}
}
}
@@ -60,10 +77,15 @@ public class MetricsController {
@GetMapping("/requests")
@Operation(summary = "POST request count",
description = "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.")
public Double getTotalRequests(@RequestParam Optional<String> endpoint) {
public Double getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
try {
Counter counter;
if (endpoint.isPresent()) {
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
if(!endpoint.get().startsWith("/")) {
endpoint = Optional.of("/" + endpoint.get());
}
System.out.println("loads " + endpoint.get() + " vs " + meterRegistry.get("http.requests").tags("uri", endpoint.get()).toString());
counter = meterRegistry.get("http.requests")
.tags("method", "POST", "uri", endpoint.get()).counter();
} else {
@@ -72,7 +94,8 @@ public class MetricsController {
}
return counter.count();
} catch (Exception e) {
return -1.0;
e.printStackTrace();
return 0.0;
}
}

View File

@@ -12,8 +12,10 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag;
@Controller
@Tag(name = "Other", description = "Other APIs")
public class OtherWebController {
@GetMapping("/compress-pdf")
@Hidden
@@ -74,7 +76,9 @@ public class OtherWebController {
@Hidden
public ModelAndView ocrPdfPage() {
ModelAndView modelAndView = new ModelAndView("other/ocr-pdf");
modelAndView.addObject("languages", getAvailableTesseractLanguages());
List<String> languages = getAvailableTesseractLanguages();
Collections.sort(languages);
modelAndView.addObject("languages", languages);
modelAndView.addObject("currentPage", "ocr-pdf");
return modelAndView;
}
@@ -108,4 +112,25 @@ public class OtherWebController {
return "other/remove-blanks";
}
@GetMapping("/multi-page-layout")
@Hidden
public String multiPageLayoutForm(Model model) {
model.addAttribute("currentPage", "multi-page-layout");
return "other/multi-page-layout";
}
@GetMapping("/scale-pages")
@Hidden
public String scalePagesFrom(Model model) {
model.addAttribute("currentPage", "scale-pages");
return "other/scale-pages";
}
@GetMapping("/auto-crop")
@Hidden
public String autoCropForm(Model model) {
model.addAttribute("currentPage", "auto-crop");
return "other/auto-crop";
}
}

View File

@@ -5,8 +5,10 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag;
@Controller
@Tag(name = "Security", description = "Security APIs")
public class SecurityWebController {
@GetMapping("/add-password")
@Hidden

View File

@@ -0,0 +1,51 @@
package stirling.software.SPDF.model;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
public class PipelineConfig {
private String name;
@JsonProperty("pipeline")
private List<PipelineOperation> operations;
private String outputDir;
@JsonProperty("outputFileName")
private String outputPattern;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<PipelineOperation> getOperations() {
return operations;
}
public void setOperations(List<PipelineOperation> operations) {
this.operations = operations;
}
public String getOutputDir() {
return outputDir;
}
public void setOutputDir(String outputDir) {
this.outputDir = outputDir;
}
public String getOutputPattern() {
return outputPattern;
}
public void setOutputPattern(String outputPattern) {
this.outputPattern = outputPattern;
}
}

View File

@@ -0,0 +1,25 @@
package stirling.software.SPDF.model;
import java.util.Map;
public class PipelineOperation {
private String operation;
private Map<String, Object> parameters;
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Map<String, Object> getParameters() {
return parameters;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
}

View File

@@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.SPDF.pdf;
import java.awt.geom.Point2D;
import java.io.IOException;

View File

@@ -0,0 +1,91 @@
package stirling.software.SPDF.utils;
import java.util.ArrayList;
import java.util.List;
public class GeneralUtils {
public static Long convertSizeToBytes(String sizeStr) {
if (sizeStr == null) {
return null;
}
sizeStr = sizeStr.trim().toUpperCase();
try {
if (sizeStr.endsWith("KB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024);
} else if (sizeStr.endsWith("MB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024);
} else if (sizeStr.endsWith("GB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024 * 1024);
} else if (sizeStr.endsWith("B")) {
return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1));
} else {
// Input string does not have a valid format, handle this case
}
} catch (NumberFormatException e) {
// The numeric part of the input string cannot be parsed, handle this case
}
return null;
}
public static List<Integer> parsePageList(String[] pageOrderArr, int totalPages) {
List<Integer> newPageOrder = new ArrayList<>();
// loop through the page order array
for (String element : pageOrderArr) {
// check if the element contains a range of pages
if (element.matches("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
// Handle page order as a function
int coefficient = 0;
int constant = 0;
boolean coefficientExists = false;
boolean constantExists = false;
if (element.contains("n")) {
String[] parts = element.split("n");
if (!parts[0].equals("") && parts[0] != null) {
coefficient = Integer.parseInt(parts[0]);
coefficientExists = true;
}
if (parts.length > 1 && !parts[1].equals("") && parts[1] != null) {
constant = Integer.parseInt(parts[1]);
constantExists = true;
}
} else if (element.contains("+")) {
constant = Integer.parseInt(element.replace("+", ""));
constantExists = true;
}
for (int i = 1; i <= totalPages; i++) {
int pageNum = coefficientExists ? coefficient * i : i;
pageNum += constantExists ? constant : 0;
if (pageNum <= totalPages && pageNum > 0) {
newPageOrder.add(pageNum - 1);
}
}
} else if (element.contains("-")) {
// split the range into start and end page
String[] range = element.split("-");
int start = Integer.parseInt(range[0]);
int end = Integer.parseInt(range[1]);
// check if the end page is greater than total pages
if (end > totalPages) {
end = totalPages;
}
// loop through the range of pages
for (int j = start; j <= end; j++) {
// print the current index
newPageOrder.add(j - 1);
}
} else {
// if the element is a single page
newPageOrder.add(Integer.parseInt(element) - 1);
}
}
return newPageOrder;
}
}

View File

@@ -0,0 +1,25 @@
package stirling.software.SPDF.utils;
import java.awt.image.BufferedImage;
public class ImageProcessingUtils {
static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) {
BufferedImage convertedImage;
switch (colorType) {
case "greyscale":
convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
break;
case "blackwhite":
convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
break;
default: // full color
convertedImage = sourceImage;
break;
}
return convertedImage;
}
}

View File

@@ -0,0 +1,5 @@
package stirling.software.SPDF.utils;
public class PDFManipulationUtils {
}

View File

@@ -92,6 +92,6 @@ public class PDFToFile {
if (tempOutputDir != null)
FileUtils.deleteDirectory(tempOutputDir.toFile());
}
return PdfUtils.bytesToWebResponse(fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM);
return WebResponseUtils.bytesToWebResponse(fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM);
}
}

View File

@@ -8,15 +8,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -30,46 +22,185 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.SimpleTextExtractionStrategy;
import stirling.software.SPDF.pdf.ImageFinder;
public class PdfUtils {
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName) throws IOException {
return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName);
public static PDRectangle textToPageSize(String size) {
switch (size) {
case "A0":
return PDRectangle.A0;
case "A1":
return PDRectangle.A1;
case "A2":
return PDRectangle.A2;
case "A3":
return PDRectangle.A3;
case "A4":
return PDRectangle.A4;
case "A5":
return PDRectangle.A5;
case "A6":
return PDRectangle.A6;
case "LETTER":
return PDRectangle.LETTER;
case "LEGAL":
return PDRectangle.LEGAL;
default:
throw new IllegalArgumentException("Invalid standard page size: " + size);
}
}
public boolean hasImageInFile(PDDocument pdfDocument, String text, String pagesToCheck) throws IOException {
PDFTextStripper textStripper = new PDFTextStripper();
String pdfText = "";
if(pagesToCheck == null || pagesToCheck.equals("all")) {
pdfText = textStripper.getText(pdfDocument);
} else {
// remove whitespaces
pagesToCheck = pagesToCheck.replaceAll("\\s+", "");
String[] splitPoints = pagesToCheck.split(",");
for (String splitPoint : splitPoints) {
if (splitPoint.contains("-")) {
// Handle page ranges
String[] range = splitPoint.split("-");
int startPage = Integer.parseInt(range[0]);
int endPage = Integer.parseInt(range[1]);
for (int i = startPage; i <= endPage; i++) {
textStripper.setStartPage(i);
textStripper.setEndPage(i);
pdfText += textStripper.getText(pdfDocument);
}
} else {
// Handle individual page
int page = Integer.parseInt(splitPoint);
textStripper.setStartPage(page);
textStripper.setEndPage(page);
pdfText += textStripper.getText(pdfDocument);
}
}
}
pdfDocument.close();
return pdfText.contains(text);
}
public static boolean hasImagesOnPage(PDPage page) throws IOException {
ImageFinder imageFinder = new ImageFinder(page);
imageFinder.processPage(page);
return imageFinder.hasImages();
}
public static boolean hasText(PDDocument document, String phrase) throws IOException {
PDFTextStripper pdfStripper = new PDFTextStripper();
String text = pdfStripper.getText(document);
return text.contains(phrase);
}
public boolean containsTextInFile(PDDocument pdfDocument, String text, String pagesToCheck) throws IOException {
PDFTextStripper textStripper = new PDFTextStripper();
String pdfText = "";
if(pagesToCheck == null || pagesToCheck.equals("all")) {
pdfText = textStripper.getText(pdfDocument);
} else {
// remove whitespaces
pagesToCheck = pagesToCheck.replaceAll("\\s+", "");
String[] splitPoints = pagesToCheck.split(",");
for (String splitPoint : splitPoints) {
if (splitPoint.contains("-")) {
// Handle page ranges
String[] range = splitPoint.split("-");
int startPage = Integer.parseInt(range[0]);
int endPage = Integer.parseInt(range[1]);
for (int i = startPage; i <= endPage; i++) {
textStripper.setStartPage(i);
textStripper.setEndPage(i);
pdfText += textStripper.getText(pdfDocument);
}
} else {
// Handle individual page
int page = Integer.parseInt(splitPoint);
textStripper.setStartPage(page);
textStripper.setEndPage(page);
pdfText += textStripper.getText(pdfDocument);
}
}
}
pdfDocument.close();
return pdfText.contains(text);
}
public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException {
return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType);
public boolean pageCount(PDDocument pdfDocument, int pageCount, String comparator) throws IOException {
int actualPageCount = pdfDocument.getNumberOfPages();
pdfDocument.close();
switch(comparator.toLowerCase()) {
case "greater":
return actualPageCount > pageCount;
case "equal":
return actualPageCount == pageCount;
case "less":
return actualPageCount < pageCount;
default:
throw new IllegalArgumentException("Invalid comparator. Only 'greater', 'equal', and 'less' are supported.");
}
}
public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType) throws IOException {
public boolean pageSize(PDDocument pdfDocument, String expectedPageSize) throws IOException {
PDPage firstPage = pdfDocument.getPage(0);
PDRectangle mediaBox = firstPage.getMediaBox();
// Return the PDF as a response
HttpHeaders headers = new HttpHeaders();
headers.setContentType(mediaType);
headers.setContentLength(bytes.length);
String encodedDocName = URLEncoder.encode(docName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
headers.setContentDispositionFormData("attachment", encodedDocName);
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
float actualPageWidth = mediaBox.getWidth();
float actualPageHeight = mediaBox.getHeight();
pdfDocument.close();
// Assumes the expectedPageSize is in the format "widthxheight", e.g. "595x842" for A4
String[] dimensions = expectedPageSize.split("x");
float expectedPageWidth = Float.parseFloat(dimensions[0]);
float expectedPageHeight = Float.parseFloat(dimensions[1]);
// Checks if the actual page size matches the expected page size
return actualPageWidth == expectedPageWidth && actualPageHeight == expectedPageHeight;
}
public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName) throws IOException {
return bytesToWebResponse(bytes, docName, MediaType.APPLICATION_PDF);
}
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI) throws IOException, Exception {
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI, String filename) throws IOException, Exception {
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
PDFRenderer pdfRenderer = new PDFRenderer(document);
int pageCount = document.getNumberOfPages();
@@ -77,7 +208,7 @@ public class PdfUtils {
// Create images of all pages
for (int i = 0; i < pageCount; i++) {
images.add(pdfRenderer.renderImageWithDPI(i, 300, colorType));
images.add(pdfRenderer.renderImageWithDPI(i, DPI, colorType));
}
if (singleImage) {
@@ -107,7 +238,7 @@ public class PdfUtils {
ImageIO.write(image, imageType, baosImage);
// Add the image to the zip file
zos.putNextEntry(new ZipEntry(String.format("page_%d.%s", i + 1, imageType.toLowerCase())));
zos.putNextEntry(new ZipEntry(String.format(filename + "_%d.%s", i + 1, imageType.toLowerCase())));
zos.write(baosImage.toByteArray());
}
}
@@ -125,6 +256,7 @@ public class PdfUtils {
public static byte[] imageToPdf(MultipartFile[] files, boolean stretchToFit, boolean autoRotate, String colorType) throws IOException {
try (PDDocument doc = new PDDocument()) {
for (MultipartFile file : files) {
String contentType = file.getContentType();
String originalFilename = file.getOriginalFilename();
if (originalFilename != null && (originalFilename.toLowerCase().endsWith(".tiff") || originalFilename.toLowerCase().endsWith(".tif")) ) {
ImageReader reader = ImageIO.getImageReadersByFormatName("tiff").next();
@@ -132,7 +264,7 @@ public class PdfUtils {
int numPages = reader.getNumImages(true);
for (int i = 0; i < numPages; i++) {
BufferedImage pageImage = reader.read(i);
BufferedImage convertedImage = convertColorType(pageImage, colorType);
BufferedImage convertedImage = ImageProcessingUtils.convertColorType(pageImage, colorType);
PDImageXObject pdImage = LosslessFactory.createFromImage(doc, convertedImage);
addImageToDocument(doc, pdImage, stretchToFit, autoRotate);
}
@@ -145,8 +277,13 @@ public class PdfUtils {
fos.write(buffer, 0, len);
}
BufferedImage image = ImageIO.read(imageFile);
BufferedImage convertedImage = convertColorType(image, colorType);
PDImageXObject pdImage = LosslessFactory.createFromImage(doc, convertedImage);
BufferedImage convertedImage = ImageProcessingUtils.convertColorType(image, colorType);
PDImageXObject pdImage;
if (contentType != null && (contentType.equals("image/jpeg"))) {
pdImage = JPEGFactory.createFromImage(doc, convertedImage);
} else {
pdImage = LosslessFactory.createFromImage(doc, convertedImage);
}
addImageToDocument(doc, pdImage, stretchToFit, autoRotate);
} catch (IOException e) {
logger.error("Error writing image to file: {}", imageFile.getAbsolutePath(), e);
@@ -163,24 +300,6 @@ public class PdfUtils {
}
}
private static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) {
BufferedImage convertedImage;
switch (colorType) {
case "greyscale":
convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
break;
case "blackwhite":
convertedImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
break;
default: // full color
convertedImage = sourceImage;
break;
}
return convertedImage;
}
private static void addImageToDocument(PDDocument doc, PDImageXObject image, boolean stretchToFit, boolean autoRotate) throws IOException {
boolean imageIsLandscape = image.getWidth() > image.getHeight();
PDRectangle pageSize = PDRectangle.A4;
@@ -217,33 +336,6 @@ public class PdfUtils {
}
}
public static X509Certificate[] loadCertificateChainFromKeystore(InputStream keystoreInputStream, String keystorePassword) throws Exception {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(keystoreInputStream, keystorePassword.toCharArray());
String alias = keystore.aliases().nextElement();
Certificate[] certChain = keystore.getCertificateChain(alias);
X509Certificate[] x509CertChain = new X509Certificate[certChain.length];
for (int i = 0; i < certChain.length; i++) {
x509CertChain[i] = (X509Certificate) certChain[i];
}
return x509CertChain;
}
public static KeyPair loadKeyPairFromKeystore(InputStream keystoreInputStream, String keystorePassword) throws Exception {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(keystoreInputStream, keystorePassword.toCharArray());
String alias = keystore.aliases().nextElement();
PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, keystorePassword.toCharArray());
Certificate cert = keystore.getCertificate(alias);
PublicKey publicKey = cert.getPublicKey();
return new KeyPair(publicKey, privateKey);
}
public static byte[] overlayImage(byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage) throws IOException {
PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes));
@@ -275,41 +367,7 @@ public class PdfUtils {
return baos.toByteArray();
}
public static ResponseEntity<byte[]> pdfDocToWebResponse(PDDocument document, String docName) throws IOException {
// Open Byte Array and save document to it
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.save(baos);
// Close the document
document.close();
return PdfUtils.boasToWebResponse(baos, docName);
}
public static Long convertSizeToBytes(String sizeStr) {
if (sizeStr == null) {
return null;
}
sizeStr = sizeStr.trim().toUpperCase();
try {
if (sizeStr.endsWith("KB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024);
} else if (sizeStr.endsWith("MB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024);
} else if (sizeStr.endsWith("GB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024 * 1024 * 1024);
} else if (sizeStr.endsWith("B")) {
return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1));
} else {
// Input string does not have a valid format, handle this case
}
} catch (NumberFormatException e) {
// The numeric part of the input string cannot be parsed, handle this case
}
return null;
}
}

View File

@@ -0,0 +1,50 @@
package stirling.software.SPDF.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
public class WebResponseUtils {
public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName) throws IOException {
return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName);
}
public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException {
return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType);
}
public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType) throws IOException {
// Return the PDF as a response
HttpHeaders headers = new HttpHeaders();
headers.setContentType(mediaType);
headers.setContentLength(bytes.length);
String encodedDocName = URLEncoder.encode(docName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
headers.setContentDispositionFormData("attachment", encodedDocName);
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName) throws IOException {
return bytesToWebResponse(bytes, docName, MediaType.APPLICATION_PDF);
}
public static ResponseEntity<byte[]> pdfDocToWebResponse(PDDocument document, String docName) throws IOException {
// Open Byte Array and save document to it
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.save(baos);
// Close the document
document.close();
return boasToWebResponse(baos, docName);
}
}

View File

@@ -1,12 +1,12 @@
spring.http.multipart.max-file-size=2GB
spring.http.multipart.max-request-size=2GB
spring.http.multipart.max-file-size=${MAX_FILE_SIZE:2000MB}
spring.http.multipart.max-request-size=${MAX_FILE_SIZE:2000MB}
multipart.enabled=true
multipart.max-file-size=2000MB
multipart.max-request-size=2000MB
multipart.max-file-size=${MAX_FILE_SIZE:2000MB}
multipart.max-request-size=${MAX_FILE_SIZE:2000MB}
spring.servlet.multipart.max-file-size=2000MB
spring.servlet.multipart.max-request-size=2000MB
spring.servlet.multipart.max-file-size=${MAX_FILE_SIZE:2000MB}
spring.servlet.multipart.max-request-size=${MAX_FILE_SIZE:2000MB}
server.forward-headers-strategy=NATIVE
@@ -22,7 +22,7 @@ server.servlet.context-path=${APP_ROOT_PATH:/}
spring.devtools.restart.enabled=true
spring.devtools.livereload.enabled=true
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.encoding=UTF-8
server.connection-timeout=${CONNECTION_TIMEOUT:5m}
spring.mvc.async.request-timeout=${ASYNC_CONNECTION_TIMEOUT:300000}

View File

@@ -24,7 +24,7 @@ close=\u0625\u063A\u0644\u0627\u0642
filesSelected = الملفات المحددة
noFavourites = لم تتم إضافة أي مفضلات
bored = الانتظار بالملل؟
alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629
#############
# HOME-PAGE #
#############
@@ -129,15 +129,37 @@ home.repair.desc = يحاول إصلاح ملف PDF تالف / معطل
home.removeBlanks.title = إزالة الصفحات الفارغة
home.removeBlanks.desc = يكتشف ويزيل الصفحات الفارغة من المستند
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.compare.title = قارن
home.compare.desc = يقارن ويظهر الاختلافات بين 2 من مستندات PDF
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf = تنزيل PDF
text=نص
font=الخط
selectFillter = - حدد -
pageNum = رقم الصفحة
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title = توقيع الشهادة
certSign.header = قم بتوقيع ملف PDF بشهادتك (العمل قيد التقدم)
certSign.selectPDF = حدد ملف PDF للتوقيع:
@@ -242,6 +264,7 @@ fileToPDF.submit=\u062A\u062D\u0648\u064A\u0644 \u0625\u0644\u0649 PDF
addImage.title=إضافة صورة
addImage.header=إضافة صورة إلى PDF
addImage.everyPage=كل صفحة؟
addImage.upload=إضافة صورة
addImage.submit=إضافة صورة
#compress
@@ -339,6 +362,9 @@ addPassword.selectText.10=منع التعديل
addPassword.selectText.11=منع تعديل التعليقات التوضيحية
addPassword.selectText.12=منع الطباعة
addPassword.selectText.13=منع طباعة تنسيقات مختلفة
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=تشفير
#watermark

View File

@@ -20,6 +20,7 @@ close=Tanca
filesSelected=fitxers seleccionats
noFavourites=No s'ha afegit cap favorit
bored=Avorrit esperant?
alphabet=Alfabet
#############
# HOME-PAGE #
#############
@@ -122,15 +123,37 @@ home.repair.desc=Intenta reparar un PDF danyat o trencat
home.removeBlanks.title=Elimina les pàgines en blanc
home.removeBlanks.desc=Detecta i elimina les pàgines en blanc d'un document
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.compare.title=Compara
home.compare.desc=Compara i mostra les diferències entre 2 documents PDF
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=Descarregueu PDF
text=Text
font=Tipus de lletra
selectFillter=-- Selecciona --
pageNum=Número de pàgina
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Significació del certificat
certSign.header=Firmar un PDF amb el vostre certificat (Treball en curs)
certSign.selectPDF=Seleccioneu un fitxer PDF per signar:
@@ -250,6 +273,7 @@ compress.submit=Comprimir
addImage.title=Afegir Imatge
addImage.header=Afegir Imatge a PDF (en construcció)
addImage.everyPage=Totes les pàgines?
addImage.upload=Afegir Imatge
addImage.submit=Afegir Imatge
@@ -337,6 +361,9 @@ addPassword.selectText.10=Evita modificacions
addPassword.selectText.11=Evita modificacions d'annotacions
addPassword.selectText.12=Evita impressió
addPassword.selectText.13=Evita impressió de diferents formats
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Encripta
#watermark

View File

@@ -20,6 +20,7 @@ close=Schließen
filesSelected=Dateien ausgewählt
noFavourites=Keine Favoriten hinzugefügt
bored=Gelangweiltes Warten?
alphabet=Alphabet
#############
# HOME-PAGE #
#############
@@ -121,15 +122,37 @@ home.repair.desc=Versucht, ein beschädigtes/kaputtes PDF zu reparieren
home.removeBlanks.title=Leere Seiten entfernen
home.removeBlanks.desc=Erkennt und entfernt leere Seiten aus einem Dokument
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.compare.title=Vergleichen
home.compare.desc=Vergleicht und zeigt die Unterschiede zwischen zwei PDF-Dokumenten an
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=PDF herunterladen
text=Text
font=Schriftart
selectFillter=-- Auswählen --
pageNum=Seitenzahl
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Zertifikatsignierung
certSign.header=Signieren Sie ein PDF mit Ihrem Zertifikat (in Arbeit)
certSign.selectPDF=Wählen Sie eine PDF-Datei zum Signieren aus:
@@ -237,6 +260,7 @@ fileToPDF.submit=In PDF konvertieren
addImage.title=Bild hinzufügen
addImage.header=Ein Bild einfügen
addImage.everyPage=Jede Seite?
addImage.upload=Bild hinzufügen
addImage.submit=Bild hinzufügen
#compress
@@ -334,6 +358,9 @@ addPassword.selectText.10=Modifizierung verhindern
addPassword.selectText.11=Ändern von Kommentaren verhindern
addPassword.selectText.12=Drucken verhindern
addPassword.selectText.13=Drucken verschiedener Formate verhindern
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Verschlüsseln
#watermark

View File

@@ -10,7 +10,7 @@ multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
imgPrompt=Select Image(s)
genericSubmit=Submit
processTimeWarning=Warning: This process can take up to a minute depending on file-size
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) :
goToPage=Go
true=True
false=False
@@ -20,6 +20,7 @@ close=Close
filesSelected=files selected
noFavourites=No favourites added
bored=Bored Waiting?
alphabet=Alphabet
#############
# HOME-PAGE #
#############
@@ -54,14 +55,11 @@ home.pdfOrganiser.title=Organise
home.pdfOrganiser.desc=Remove/Rearrange pages in any order
home.addImage.title=Add image
home.addImage.desc=Adds a image onto a set location on the PDF (Work in progress)
home.addImage.desc=Adds a image onto a set location on the PDF
home.watermark.title=Add Watermark
home.watermark.desc=Add a custom watermark to your PDF document.
home.remove-watermark.title=Remove Watermark
home.remove-watermark.desc=Remove watermarks from your PDF document.
home.permissions.title=Change Permissions
home.permissions.desc=Change the permissions of your PDF document
@@ -128,6 +126,16 @@ home.compare.desc=Compares and shows the differences between 2 PDF Documents
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of a page and/or its contents.
home.pipeline.title=Pipeline
home.pipeline.desc=Pipeline desc.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=Download PDF
text=Text
@@ -135,6 +143,19 @@ font=Font
selectFillter=-- Select --
pageNum=Page Number
pipeline.title=Pipeline
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Certificate Signing
certSign.header=Sign a PDF with your certificate (Work in progress)
certSign.selectPDF=Select a PDF File for Signing:
@@ -258,6 +279,7 @@ compress.submit=Compress
addImage.title=Add Image
addImage.header=Add image to PDF
addImage.everyPage=Every Page?
addImage.upload=Add image
addImage.submit=Add image
@@ -333,10 +355,10 @@ pdfToImage.submit=Convert
addPassword.title=Add Password
addPassword.header=Add password (Encrypt)
addPassword.selectText.1=Select PDF to encrypt
addPassword.selectText.2=Password
addPassword.selectText.2=User Password
addPassword.selectText.3=Encryption Key Length
addPassword.selectText.4=Higher values are stronger, but lower values have better compatibility.
addPassword.selectText.5=Permissions to set
addPassword.selectText.5=Permissions to set (Recommended to be used along with Owner password)
addPassword.selectText.6=Prevent assembly of document
addPassword.selectText.7=Prevent content extraction
addPassword.selectText.8=Prevent extraction for accessibility
@@ -345,6 +367,9 @@ addPassword.selectText.10=Prevent modification
addPassword.selectText.11=Prevent annotation modification
addPassword.selectText.12=Prevent printing
addPassword.selectText.13=Prevent printing different formats
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Encrypt
#watermark

View File

@@ -11,7 +11,7 @@ imgPrompt=Seleccionar Imagen(es)
genericSubmit=Enviar
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma):
goToPage=Ir
goToPage=Ir a
true=Verdadero
false=Falso
unknown=Desconocido
@@ -20,10 +20,11 @@ close=Cerrar
filesSelected=archivos seleccionados
noFavourites=No se agregaron favoritos
bored=¿Aburrido de esperar?
alphabet=Alfabeto
#############
# HOME-PAGE #
#############
home.desc=Tu autohospedada ventanilla única para todas tus necesidades PDF.
home.desc=Tu ventanilla única autohospedada para todas tus necesidades PDF
navbar.convert=Convertir
navbar.security=Seguridad
@@ -35,19 +36,19 @@ home.multiTool.title=Multi-herramienta PDF
home.multiTool.desc=Combinar, rotar, reorganizar y eliminar páginas
home.merge.title=Unir
home.merge.desc=Unir fácilmente múltiples PDFs en uno.
home.merge.desc=Unir fácilmente múltiples PDFs en uno
home.split.title=Dividir
home.split.desc=Dividir PDFs en múltiples documentos
home.rotate.title=Rotar
home.rotate.desc=Rotar fácilmente tus PDFs.
home.rotate.desc=Rotar fácilmente tus PDFs
home.imageToPdf.title=Imagen a PDF
home.imageToPdf.desc=Convertir una imagen (PNG, JPEG, GIF) a PDF.
home.imageToPdf.desc=Convertir una imagen (PNG, JPEG, GIF) a PDF
home.pdfToImage.title=PDF a Imagen
home.pdfToImage.desc=Convertir un PDF a una imagen. (PNG, JPEG, GIF)
home.pdfToImage.desc=Convertir un PDF a una imagen (PNG, JPEG, GIF)
home.pdfOrganiser.title=Organizador
home.pdfOrganiser.desc=Eliminar/Reorganizar páginas en cualquier orden
@@ -56,37 +57,37 @@ home.addImage.title=Agregar imagen al PDF
home.addImage.desc=Agregar una imagen en una ubicación establecida en el PDF (trabajo en progreso)
home.watermark.title=Añadir marca de agua
home.watermark.desc=Añadir una marca de agua predefinida a tu documento PDF.
home.watermark.desc=Añadir una marca de agua predefinida al documento PDF
home.remove-watermark.title=Eliminar marca de agua
home.remove-watermark.desc=Eliminar marcas de agua de tu documento PDF.
home.remove-watermark.desc=Eliminar marca de agua de tu documento PDF
home.permissions.title=Cambiar Permisos
home.permissions.desc=Cambiar los permisos de tu documento PDF
home.permissions.title=Cambiar permisos
home.permissions.desc=Cambiar los permisos del documento PDF
home.removePages.title=Eliminar
home.removePages.desc=Eliminar páginas no deseadas de tu documento PDF.
home.removePages.desc=Eliminar páginas no deseadas del documento PDF
home.addPassword.title=Añadir Contraseña
home.addPassword.desc=Encriptar el documento PDF con una contraseña.
home.addPassword.title=Añadir contraseña
home.addPassword.desc=Encriptar el documento PDF con una contraseña
home.removePassword.title=Eliminar Contraseña
home.removePassword.desc=Eliminar la contraseña del documento PDF.
home.removePassword.title=Eliminar contraseña
home.removePassword.desc=Eliminar la contraseña del documento PDF
home.compressPdfs.title=Comprimir
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del fichero.
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del fichero
home.changeMetadata.title=Cambiar Metadatos
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF.
home.changeMetadata.title=Cambiar metadatos
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
home.fileToPDF.title=Convertir fichero a PDF
home.fileToPDF.desc=Convertir casi cualquier archivo a PDF (DOCX, PNG, XLS, PPT, TXT y más)
home.ocr.title=Ejecutar OCR en PDF y/o escaneos de limpieza
home.ocr.desc=Escaneos de limpieza y detecta texto de imágenes dentro de un PDF y lo vuelve a agregar como texto.
home.ocr.desc=Escaneos de limpieza y detectar texto de imágenes dentro de un PDF y volver a agregarlo como texto
home.extractImages.title=Extraer imágenes
home.extractImages.desc=Extraer todas las imágenes de un PDF y guardarlas en zip
home.extractImages.desc=Extraer todas las imágenes de un PDF y guardarlas en ZIP
home.pdfToPDFA.title=Convertir PDF a PDF/A
home.pdfToPDFA.desc=Convertir PDF a PDF/A para almacenamiento a largo plazo
@@ -110,19 +111,30 @@ home.ScannerImageSplit.title=Detectar/Dividir fotos escaneadas
home.ScannerImageSplit.desc=Dividir varias fotos dentro de una foto/PDF
home.sign.title=Firmar
home.sign.desc=Añade firma a PDF mediante dibujo, texto o imagen
home.sign.desc=Añadir firma a PDF mediante dibujo, texto o imagen
home.flatten.title=Aplanar
home.flatten.desc=Eliminar todos los elementos y formularios interactivos de un PDF
home.repair.title=Reparar
home.repair.desc=Intenta reparar un PDF corrupto/roto
home.repair.desc=Intentar reparar un PDF corrupto/roto
home.removeBlanks.title=Eliminar páginas en blanco
home.removeBlanks.descdetecta y elimina páginas en blanco de un documento
home.removeBlanks.desc=Detectar y eliminar páginas en blanco de un documento
home.certSign.title=Firmar con certificado
home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12)
home.compare.title=Comparar
home.compare.desc=Compara y muestra las diferencias entre 2 documentos PDF
home.compare.desc=Comparar y mostrar las diferencias entre 2 documentos PDF
home.pageLayout.title=Diseño de varias páginas
home.pageLayout.desc=Unir varias páginas de un documento PDF en una sola página
home.scalePages.title=Escalar/ajustar tamaño de página
home.scalePages.desc=Escalar/cambiar el tamaño de una pagina y/o su contenido
error.pdfPassword=El documento PDF está protegido con contraseña y no se ha proporcionado o es incorrecta
downloadPdf=Descargar PDF
text=Texto
@@ -130,8 +142,19 @@ font=Fuente
selectFilter=-- Seleccionar --
pageNum=Número de página
pageLayout.title=Diseño de varias páginas
pageLayout.header=Diseño de varias páginas
pageLayout.pagesPerSheet=Páginas por hoja:
pageLayout.submit=Entregar
scalePages.title=Ajustar escala de la página
scalePages.header=Adjustar escala de la página
scalePages.pageSize=Tamaño de la página del documento
scalePages.scaleFactor=Nivel de zoom (recorte) de la página
scalePages.submit=Entregar
certSign.title=Firma de certificado
certSign.header=Firme un PDF con su certificado (Trabajo en progreso)
certSign.header=Firmar un PDF con su certificado (Trabajo en progreso)
certSign.selectPDF=Seleccione un archivo PDF para firmar:
certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der):
certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der):
@@ -175,13 +198,13 @@ flatten.header=Acoplar archivos PDF
flatten.submit=Aplanar
ScannerImageSplit.selectText.1=Umbral de ángulo:
ScannerImageSplit.selectText.2=Establece el ángulo absoluto mínimo requerido para rotar la imagen (predeterminado: 10).
ScannerImageSplit.selectText.2=Establecer el ángulo absoluto mínimo requerido para rotar la imagen (predeterminado: 10).
ScannerImageSplit.selectText.3=Tolerancia:
ScannerImageSplit.selectText.4=Determina el rango de variación de color alrededor del color de fondo estimado (predeterminado: 30).
ScannerImageSplit.selectText.4=Determinar el rango de variación de color alrededor del color de fondo estimado (predeterminado: 30).
ScannerImageSplit.selectText.5=Área mínima:
ScannerImageSplit.selectText.6=Establece el umbral mínimo de área para una foto (predeterminado: 10000).
ScannerImageSplit.selectText.6=Establecer el umbral mínimo de área para una foto (predeterminado: 10000).
ScannerImageSplit.selectText.7=Área de contorno mínima:
ScannerImageSplit.selectText.8=Establece el umbral mínimo del área de contorno para una foto
ScannerImageSplit.selectText.8=Establecer el umbral mínimo del área de contorno para una foto
ScannerImageSplit.selectText.9=Tamaño del borde:
ScannerImageSplit.selectText.10=Establece el tamaño del borde agregado y eliminado para evitar bordes blancos en la salida (predeterminado: 1).
@@ -189,10 +212,10 @@ navbar.settings=Ajustes
settings.title=Ajustes
settings.update=Actualización disponible
settings.appVersion=Versión de la aplicación:
settings.downloadOption.title=Elige la opción de descarga (para descargas de un solo archivo sin ZIP):
settings.downloadOption.1=Abre en la misma ventana
settings.downloadOption.2=Abre en una nueva ventana
settings.downloadOption.3=Descarga el fichero
settings.downloadOption.title=Elegir la opción de descarga (para descargas de un solo archivo sin ZIP):
settings.downloadOption.1=Abrir en la misma ventana
settings.downloadOption.2=Abrir en una nueva ventana
settings.downloadOption.3=Descargar el fichero
settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descargados
@@ -201,54 +224,55 @@ settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descarga
#OCR
ocr.title=OCR / Escaneo de limpieza
ocr.header=Escaneos de limpieza / OCR (Reconocimiento óptico de caracteres)
ocr.selectText.1=Selecciona los idiomas que se detectarán en el PDF (Los enumerados son los detectados actualmente):
ocr.selectText.2=Produzca un archivo de texto que contenga texto OCR junto con el PDF editado con OCR
ocr.selectText.3=Corrija las páginas que se escanearon en un ángulo torcido girándolas nuevamente a su lugar
ocr.selectText.4=Limpie la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo. (Sin cambio de salida)
ocr.selectText.5=Limpie la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo, mantiene la limpieza en la salida.
ocr.selectText.6=Ignora las páginas que tienen texto interactivo, solo las páginas OCR que son imágenes
ocr.selectText.7=Fuerza OCR, OCR eliminará en cada página todo el texto original
ocr.selectText.8=Normal (Se producirá un error si el PDF contiene texto)
ocr.selectText.9=Ajustes Adicionales
ocr.selectText.1=Seleccionar los idiomas que se detectarán en el PDF (Los enumerados son los detectados actualmente):
ocr.selectText.2=Producir un archivo de texto que contenga texto OCR junto con el PDF editado con OCR
ocr.selectText.3=Corregir las páginas que se escanearon en un ángulo torcido girándolas nuevamente a su lugar
ocr.selectText.4=Limpiar la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo (Sin cambio de salida)
ocr.selectText.5=Limpiar la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo, mantiene la limpieza en la salida.
ocr.selectText.6=Ignorar las páginas que tienen texto interactivo, solo las páginas OCR que son imágenes
ocr.selectText.7=Forzar OCR, OCR eliminará en cada página todo el texto original
ocr.selectText.8=Normal (se producirá un error si el PDF contiene texto)
ocr.selectText.9=Ajustes adicionales
ocr.selectText.10=Modo OCR
ocr.selectText.11=Eliminar imágenes después de OCR (Elimina TODAS las imágenes, solo es útil si es parte del paso de conversión)
ocr.selectText.12=Tipo de procesamiento (avanzado)
ocr.help=Lea esta documentación sobre cómo usar esto para otros idiomas y/o no usarlo en docker
ocr.credit=Este servicio utiliza OCRmyPDF y Tesseract para OCR.
ocr.submit=Procesa PDF con OCR
ocr.help=Lea esta documentación sobre cómo usar esto para otros idiomas y/o no usarlo en Docker
ocr.credit=Este servicio utiliza OCRmyPDF y Tesseract para OCR
ocr.submit=Procesar PDF con OCR
extractImages.title=Extraer imágenes
extractImages.header=Extraer imágenes
extractImages.selectText=Selecciona el formato de imagen para convertir las imágenes extraídas
extractImages.selectText=Seleccionar el formato de imagen para convertir las imágenes extraídas
extractImages.submit=Extraer
#File to PDF
fileToPDF.title=Fichero a PDF
fileToPDF.header=Convierte cualquier fichero a PDF
fileToPDF.credit=Este servicio usa LibreOffice y Unoconv para la conversión de ficheros.
fileToPDF.supportedFileTypes=Los tipos de ficheros soportados deben incluir los de abajo; sin embargo para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice
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 ficheros
fileToPDF.supportedFileTypes=Los tipos de ficheros soportados deben incluir los de abajo; sin embargo, para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice
fileToPDF.submit=Convertir a PDF
#compress
compress.title=Comprimir
compress.header=Comprimir PDF
compress.credit=Este servicio utiliza Ghostscript para compresión/optimización de PDF.
compress.credit=Este servicio utiliza Ghostscript para compresión/optimización de PDF
compress.selectText.1=Modo manual - De 1 a 4
compress.selectText.2=Nivel de optimización:
compress.selectText.3=4 (Terrible para imágenes de texto)
compress.selectText.4=Modo automático: ajusta automáticamente la calidad para que el PDF tenga el tamaño exacto
compress.selectText.5=Tamaño de PDF esperado (por ejemplo, 25 MB, 10,8 MB, 25 KB)
compress.selectText.5=Tamaño esperado del PDF (por ejemplo, 25 MB, 10.8 MB, 25 KB)
compress.submit=Comprimir
#Add image
addImage.title=Añadir Imagen
addImage.header=Añadir image de PDF
addImage.title=Añadir imagen
addImage.header=Añadir imagen de PDF
addImage.everyPage=¿Todas las páginas?
addImage.upload=Añadir imagen
addImage.submit=Añadir imagen
@@ -269,13 +293,13 @@ multiTool.header=Multi-herramienta PDF
#pageRemover
pageRemover.title=Eliminador de páginas
pageRemover.header=Eliminador de páginas PDF
pageRemover.pagesToDelete=Páginas a eliminar (Introduzca una lista de números de página separados por coma):
pageRemover.pagesToDelete=Páginas a eliminar (introducir una lista de números de página separados por coma):
pageRemover.submit=Eliminar Páginas
#rotate
rotate.title=Rotar PDF
rotate.header=Rotar PDF
rotate.SeleccionaAngle=Seleccionar ángulo de rotación (múltiple de 90 grados):
rotate.SeleccionaAngle=Seleccionar ángulo de rotación (múltiplo de 90 grados):
rotate.submit=Rotar
@@ -284,7 +308,7 @@ rotate.submit=Rotar
#merge
split.title=Dividir PDF
split.header=Dividir PDF
split.desc.1=Los números que selecciones son el número de página en el que desea hacer una división
split.desc.1=Los números que seleccione son el número de página en el que desea hacer una división
split.desc.2=Como tal, seleccionar 1,3,7-8 dividiría un documento de 10 páginas en 6 archivos PDF separados con:
split.desc.3=Documento #1: Página 1
split.desc.4=Documento #2: Páginas 2 y 3
@@ -292,7 +316,7 @@ split.desc.5=Documento #3: Páginas 4, 5 y 6
split.desc.6=Documento #4: Página 7
split.desc.7=Documento #5: Página 8
split.desc.8=Documento #6: Páginas 9 y 10
split.splitPages=Introduce las páginas para dividir:
split.splitPages=Introducir las páginas para dividir:
split.submit=Dividir
@@ -302,7 +326,7 @@ imageToPDF.header=Imagen a PDF
imageToPDF.submit=Convertir
imageToPDF.selectText.1=Estirar para ajustar
imageToPDF.selectText.2=Rotación automática del PDF
imageToPDF.selectText.3=Lógica de archivos múltiples (Únicamente activado si funciona con multiples imágenes)
imageToPDF.selectText.3=Lógica de archivos múltiples (únicamente activado si funciona con multiples imágenes)
imageToPDF.selectText.4=Unir en un único archivo PDF
imageToPDF.selectText.5=Convertir a PDFs separados
@@ -311,21 +335,21 @@ pdfToImage.title=PDF a Imagen
pdfToImage.header=PDF a Imagen
pdfToImage.selectText=Formato de Imagen
pdfToImage.singleOrMultiple=Tipo resultante de imagen
pdfToImage.single=Una Imagen Grande Única
pdfToImage.multi=Múltiples Imágenes
pdfToImage.single=Una única imagen grande
pdfToImage.multi=Múltiples imágenes
pdfToImage.colorType=Tipo de color
pdfToImage.color=Color
pdfToImage.grey=Escala de Grises
pdfToImage.blackwhite=Blanco y Negro (¡Puedes perder datos!)
pdfToImage.grey=Escala de grises
pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!)
pdfToImage.submit=Convertir
#addPassword
addPassword.title=Añadir Contraseña
addPassword.header=Añadir contraseña (Encriptar)
addPassword.title=Añadir contraseña
addPassword.header=Añadir contraseña (encriptar)
addPassword.selectText.1=Seleccionar PDF para encriptar
addPassword.selectText.2=Contraseña
addPassword.selectText.3=Longitud de la clave de cifrado
addPassword.selectText.4=Valores altos son más fuertes, pero valores bajos tienen mejor compatibilidad.
addPassword.selectText.4=Valores altos son más fuertes, pero valores bajos tienen mejor compatibilidad
addPassword.selectText.5=Permisos para establecer
addPassword.selectText.6=Impedir el ensamblaje del documento
addPassword.selectText.7=Impedir la extracción de contenido
@@ -335,6 +359,9 @@ addPassword.selectText.10=Impedir modificación
addPassword.selectText.11=Impedir modificación de anotaciones
addPassword.selectText.12=Impedir imprimir
addPassword.selectText.13=Impedir imprimir diferentes formatos
addPassword.selectText.14=Contraseña
addPassword.selectText.15=Restringe qué se puede hacer con el documento una vez abierto (no soportado por todos los lectores)
addPassword.selectText.16=Restringe la apertura del propio documento
addPassword.submit=Encriptar
#watermark
@@ -357,8 +384,8 @@ remove-watermark.selectText.2=Texto de la marca de agua:
remove-watermark.submit=Eliminar marca de agua
#Change permissions
permissions.title=Cambiar Permisos
permissions.header=Cambiar Permisos
permissions.title=Cambiar permisos
permissions.header=Cambiar permisos
permissions.warning=Advertencia: para que estos permisos no se puedan cambiar, se recomienda configurarlos con una contraseña a través de la página de cambio de contraseña
permissions.selectText.1=Seleccionar PDF para cambiar los permisos
permissions.selectText.2=Permisos a establecer
@@ -374,21 +401,21 @@ permissions.submit=Cambiar
#remove password
removePassword.title=Eliminar contraseña
removePassword.header=Eliminar contraseña (Desencriptar)
removePassword.selectText.1=Seleccionar PDF para Desencriptar
removePassword.header=Eliminar contraseña (desencriptar)
removePassword.selectText.1=Seleccionar PDF para desencriptar
removePassword.selectText.2=Contraseña
removePassword.submit=Eliminar
changeMetadata.title=Cambiar Metadatos
changeMetadata.header=Cambiar Metadatos
changeMetadata.title=Cambiar metadatos
changeMetadata.header=Cambiar metadatos
changeMetadata.selectText.1=Editar las variables que desea cambiar
changeMetadata.selectText.2=Eliminar todos los metadatos
changeMetadata.selectText.3=Mostrar metadatos personalizados:
changeMetadata.author=Autor:
changeMetadata.creationDate=Fecha de Creación (aaaa/MM/dd HH:mm:ss):
changeMetadata.creationDate=Fecha de creación (aaaa/MM/dd HH:mm:ss):
changeMetadata.creator=Creador:
changeMetadata.keywords=Palabras clave:
changeMetadata.modDate=Fecha de Modificación (aaaa/MM/dd HH:mm:ss):
changeMetadata.modDate=Fecha de modificación (aaaa/MM/dd HH:mm:ss):
changeMetadata.producer=Productor:
changeMetadata.subject=Asunto:
changeMetadata.title=Título:
@@ -415,29 +442,29 @@ pdfToPDFA.submit=Convertir
PDFToWord.title=PDF a Word
PDFToWord.header=PDF a Word
PDFToWord.selectText.1=Formato de archivo de salida
PDFToWord.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
PDFToWord.credit=Este servicio utiliza LibreOffice para la conversión de archivos
PDFToWord.submit=Convertir
PDFToPresentation.title=PDF a presentación
PDFToPresentation.header=PDF a presentación
PDFToPresentation.selectText.1=Formato de archivo de salida
PDFToPresentation.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
PDFToPresentation.credit=Este servicio utiliza LibreOffice para la conversión de archivos
PDFToPresentation.submit=Convertir
PDFToText.title=PDF a TXT/RTF
PDFToText.header=PDF a TXT/RTF
PDFToText.selectText.1=Formato de archivo de salida
PDFToText.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
PDFToText.credit=Este servicio utiliza LibreOffice para la conversión de archivos
PDFToText.submit=Convertir
PDFToHTML.title=PDF a HTML
PDFToHTML.header=PDF a HTML
PDFToHTML.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
PDFToHTML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
PDFToHTML.submit=Convertir
PDFToXML.title=PDF a XML
PDFToXML.header=PDF a XML
PDFToXML.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
PDFToXML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
PDFToXML.submit=Convertir

View File

@@ -0,0 +1,470 @@
###########
# Generic #
###########
# the direction that the language is written (ltr = left to right, rtl = right to left)
language.direction=ltr
pdfPrompt=Hautatu PDFa(k)
multiPdfPrompt=Hautatu PDFak (2+)
multiPdfDropPrompt=Hautatu (edo arrastatu eta jaregin) nahi dituzun PDFak
imgPrompt=Hautatu Irudia(k)
genericSubmit=Bidali
processTimeWarning=Oharra: prozesu honetarako minutu bat ere beharko da fitxategiaren tamaiaren arabera
pageOrderPrompt=Orrialdeen ordena (sartu komaz bereizitako orrialde-zenbakien zerrenda)
goToPage=Joan
true=Egiazkoa
false=Faltsua
unknown=Ezezaguna
save=Gorde
close=Itxi
filesSelected=Hautatutako fitxategiak
noFavourites=Ez dira gogokoak gehitu
bored=Itxaroten aspertuta?
alphabet=Alfabetoa
#############
# HOME-PAGE #
#############
home.desc=Zure leihatila bakarra autoostatatua zure PDF behar guztietarako
navbar.convert=Bihurtu
navbar.security=Segurtasuna
navbar.other=Beste bat
navbar.darkmode=Modu iluna
navbar.pageOps=Orrialde-eragiketak
home.multiTool.title=Erabilera anitzeko tresna PDF
home.multiTool.desc= Orriak konbinatu, biratu, berrantolatu eta ezabatu
home.merge.title=Elkartu
home.merge.desc=Elkartu zenbait PDF dokumentu bakar batean modu errazean
home.split.title=Zatitu
home.split.desc=Zatitu PDFak zenbait dokumentutan
home.rotate.title=Biratu
home.rotate.desc=Biratu PDFak modu errazean
home.imageToPdf.title=Irudia PDF bihurtu
home.imageToPdf.desc=Irudi bat(PNG, JPEG, GIF)PDF bihurtu
home.pdfToImage.title=PDFa irudi bihurtu
home.pdfToImage.desc=PDF bat irudi (PNG, JPEG, GIF) bihurtu
home.pdfOrganiser.title=Antolatzailea
home.pdfOrganiser.desc=Ezabatu/Berrantolatu orrialdeak edozein ordenatan
home.addImage.title=Gehitu irudia PDFari
home.addImage.desc=Gehitu irudi bat PDFan ezarritako kokaleku batean (lanean)
home.watermark.title=Gehitu ur-marka
home.watermark.desc=Gehitu aurrez zehaztutako ur-marka bat PFD dokumentuari
home.remove-watermark.title= Ezabatu ur-marka
home.remove-watermark.desc= Ezabatu ur-marka PDF dokumentutik
home.permissions.title=Aldatu baimenak
home.permissions.desc=Aldatu PDF dokumentuaren baimenak
home.removePages.title=Ezabatu
home.removePages.desc=Ezabatu nahi ez dituzun orrialdeak PDF dokumentutik
home.addPassword.title=Gehitu pasahitza
home.addPassword.desc=Enkriptatu PDF dokumentua pasahitz batekin
home.removePassword.title=Ezabatu pasahitza
home.removePassword.desc=Ezabatu pasahitza PDF dokumentutik
home.compressPdfs.title=Konprimatu
home.compressPdfs.desc=Konprimatu PDFak fitxategiaren tamaina murrizteko
home.changeMetadata.title=Aldatu metadatuak
home.changeMetadata.desc=Aldatu/Ezabatu/Gehitu metadatuak PDF dokumentuari
home.fileToPDF.title=Fitxategia PDF bihurtu
home.fileToPDF.desc=PDF bihurtu ia edozein fitxategi (DOCX, PNG, XLS, PPT, TXT eta gehiago)
home.ocr.title=OCR exekutatu PDFan eta/edo garbiketa-eskaneatzeak
home.ocr.desc=Garbiketa-eskaneatzeak eta irudi-testuak detektatu PDF baten barruan eta berriz ere gehitu testu gisa
home.extractImages.title=Atera irudiak
home.extractImages.desc=Atera irudi guztiak PDF batetik eta ZIPen gorde
home.pdfToPDFA.title=PDFa PDF/A bihurtu
home.pdfToPDFA.desc=PDFa PDF/A bihurtu luzaro biltegiratzeko
home.PDFToWord.title=PDFa Word Bihurtu
home.PDFToWord.desc=PDF formatuak Word bihurtu (DOC, DOCX y ODT)
home.PDFToPresentation.title=PDFa aurkezpen bihurtu
home.PDFToPresentation.desc=PDFa aurkezpen formatu bihurtu (PPT, PPTX y ODP)
home.PDFToText.title=PDFa TXT edo RTF bihurtu
home.PDFToText.desc=PDFa TXT edo RTF formatu bihurtu
home.PDFToHTML.title=PDFa HTML bihurtu
home.PDFToHTML.desc=PDFa HTML formatu bihurtu
home.PDFToXML.title=PDFa XML bihurtu
home.PDFToXML.desc=PDFa XML formatu bihurtu
home.ScannerImageSplit.title=Detektatu/Zatitu argazki eskaneatuak
home.ScannerImageSplit.desc=Hainbat argazki zatitu argazki/PDF baten barruan
home.sign.title=Sinatu
home.sign.desc=Gehitu sinadura PDFari marrazki, testu edo irudi bidez
home.flatten.title=Lautu
home.flatten.desc=PDF batetik elementu eta inprimaki interaktibo guztiak ezabatu
home.repair.title=Konpondu
home.repair.desc=Saiatu PDF hondatu/kaltetu bat konpontzen
home.removeBlanks.title=Ezabatu orrialde zuriak
home.removeBlanks.desc=Detektatu orrialde zuriak eta dokumentutik ezabatu
home.certSign.title=Sinatu ziurtagiriarekin
home.certSign.desc=Sinatu PDF bat Ziurtagiri/Gako batekin (PEM/P12)
home.compare.title=Konparatu
home.compare.desc=Konparatu eta erakutsi 2 PDF dokumenturen aldeak
home.pageLayout.title=Zenbait orrialderen diseinua
home.pageLayout.desc=Elkartu orri bakar batean PDF dokumentu baten zenbait orrialde
home.scalePages.title=Eskalatu/Doitu orrialdearen tamaina
home.scalePages.desc=Eskalatu/Aldatu orrialde baten tamaina eta/edo edukia
error.pdfPassword=PDF dokumentua pasahitzarekin babestuta dago eta pasahitza ez da sartu edo akastuna da
downloadPdf=PDFa deskargatu
text=Testua
font=Letra-tipoa
selectFilter=-- Hautatu --
pageNum=Orrialde-zenbakia
pageLayout.title=Hainbat orrialderen diseinua
pageLayout.header=Hainbat orrialderen diseinua
pageLayout.pagesPerSheet=Orrialdeak orriko:
pageLayout.submit=Entregatu
scalePages.title=Doitu orrialdearen eskala
scalePages.header=Doitu orrialdearen eskala
scalePages.pageSize=Dokumentuaren orrialdearen tamaina
scalePages.scaleFactor=Orriaren zoom maila (moztea)
scalePages.submit=Entregatu
certSign.title=Ziurtagiriaren sinadura
certSign.header=Sinatu PDF bat haren ziurtagiriarekin (lanean)
certSign.selectPDF=Hautatu PDF fitxategi bat sinatzeko:
certSign.selectKey=Hautatu gako pribatuko fitxategia (PKCS#8 formatua, .pem edo .der izan liteke):
certSign.selectCert=Hautatu ziurtagiridun fitxategia (X.509 formatua, .pem edo .der izan liteke):
certSign.selectP12=Hautatu gakoak gordetzeko fitxategia PKCS#12 (.p12 o .pfx) (Aukerakoa, ematen bada, gako pribatua eta ziurtagiria izan beharko ditu):
certSign.certType=Ziurtagiri-mota
certSign.password=Sartu zure gakoen biltegia edo gako pribatuko pasahitza (hala badagokio):
certSign.showSig=Erakutsi sinadura
certSign.reason=Arrazoia
certSign.location=Kokalekua
certSign.name=Izena
certSign.submit=Sinatu PDFa
removeBlanks.title=Ezabatu zuriuneak
removeBlanks.header=Ezabatu orrialde zuriak
removeBlanks.threshold=Gutxieneko balioa:
removeBlanks.thresholdDesc=Pixel bat zeinen zuri izan behar den ezartzeko gutxieneko balioa
removeBlanks.whitePercent=Zuriaren protzentajea (%):
removeBlanks.whitePercentDesc=Zuria izan behar den orriaren ehunekoa ezabatua izan dadin
removeBlanks.submit=Ezabatu zuriuneak
compare.title=Konparatu
compare.header=Konparatu PDF fitxategiak
compare.document.1=1. dokumentua
compare.document.2=2. dokumentua
compare.submit=Konparatu
sign.title=Sinatu
sign.header=Sinatu PDF fitxategiak
sign.upload=Igo irudia
sign.draw=Marraztu sinadura
sign.text=Testua sartzea
sign.clear=Garbitu
sign.add=Gehitu
repair.title=Konpondu
repair.header=Konpondu PDF fitxategiak
repair.submit=Konpondu
flatten.title=Lautu
flatten.header=Akoplatu PDF fitxategiak
flatten.submit=Lautu
ScannerImageSplit.selectText.1=Angeluaren gutxieneko balioa:
ScannerImageSplit.selectText.2=Ezarri eskatutako gutxieneko angelu absolutua irudia biratzeko (lehenetsia: 10).
ScannerImageSplit.selectText.3=Tolerantzia:
ScannerImageSplit.selectText.4=Ezarri kalkulatutako atzeko kolorearen inguruko kolorearen aldakuntza tartea (lehenetsia: 30).
ScannerImageSplit.selectText.5=Gutxieneko area:
ScannerImageSplit.selectText.6=Ezarri arearen gutxieneko balioa argazki batentzat (lehenetsia: 10000).
ScannerImageSplit.selectText.7=Inguruko area gutxienekoa:
ScannerImageSplit.selectText.8=Ezarri inguruko arearen gutxieneko balioa argazki batentzat
ScannerImageSplit.selectText.9=Ertzaren tamaina:
ScannerImageSplit.selectText.10=Ezarri gehitutako eta ezabatutako ertzaren tamaina irteeran ertz zuriak saihesteko (lehenetsia: 1).
navbar.settings=Ezarpenak
settings.title=Ezarpenak
settings.update=Eguneratze eskuragarria
settings.appVersion=Aplikazioaren bertsioa:
settings.downloadOption.title=Hautatu deskargatzeko aukera (fitxategi bakarra deskargatzeko ZIP gabe):
settings.downloadOption.1=Ireki leiho berean
settings.downloadOption.2=Ireki leiho berrian
settings.downloadOption.3=Deskargatu fitxategia
settings.zipThreshold=ZIP fitxategiak deskargatutako fitxategi kopurua gainditzen denean
#OCR
ocr.title=OCR / Garbiketa-eskaneatzea
ocr.header=Garbiketa-eskaneatzea / OCR (Karaktere-ezagutze optikoa)
ocr.selectText.1=Hautatu PDFan detektatuko diren hizkuntzak (zerrendatutakoak gaur egun detektatzen dituenak dira):
ocr.selectText.2=Sortu OCR testua duen testu-fitxategi bat OCR-ren bidez editatutako PDFarekin batera
ocr.selectText.3=Zuzendu angelu okertu batean eskaneatu ziren orrialdeak berriro beren lekura biratuta
ocr.selectText.4=Garbitu orrialdea OCRk hondoko zaratan testua aurkitzeko probabilitate txikiagoa izan dezan (Irteeran aldatu gabe)
ocr.selectText.5=Garbitu orrialdea OCRk hondoko zaratan testua aurkitzeko probabilitate txikiagoa izan dezan, irteeran garbi mantentzen du.
ocr.selectText.6=Alde batera utzi testu interaktiboa duten orrialdeak, bakarrik irudi diren OCR orrialdeak
ocr.selectText.7=OCR behartu, OCRk orrialde bakoitzean jatorrizko testu guztia ezabatuko du
ocr.selectText.8=Normala (Errorea gertatuko da PDFak testua baldin badu)
ocr.selectText.9=Ezarpen gehigarriak
ocr.selectText.10=OCR modua
ocr.selectText.11=Irudiak ezabatu OCR-ren ondoren (Irudi GUZTIAK ezabatzen ditu, bakarrik da erabilgarri bihurketa urratsaren parte baldin bada)
ocr.selectText.12=Prozesaketa-mota (aurreratua)
ocr.help=Irakurri honen erabilerari buruzko dokumentazioa beste hizkuntza batzuetarako eta/edo ez erabili Docker-en
ocr.credit=Zerbitzu honek OCRmyPDF eta OCR-rako Tesseract erabiltzen ditu
ocr.submit=PDF prozesatu OCR-rekin
extractImages.title=Atera irudiak
extractImages.header=Atera irudiak
extractImages.selectText=Hautatu irudi-formatua ateratako irudiak bihurtzeko
extractImages.submit=Atera
#File to PDF
fileToPDF.title=Fitxategia PDF bihurtu
fileToPDF.header=Edozein fitxategi PDF bihurtu
fileToPDF.credit=Zerbitzu honek LibreOffice eta Unoconv erabiltzen ditu fitxategiak bihurtzeko
fileToPDF.supportedFileTypes=Jasandako fitxategi-motek behekoak barne hartu behar dituzte; hala ere, jasandako formatuen zerrenda osoa eta eguneratua izateko, kontsultatu, mesedez, LibreOffice-en dokumentazioa
fileToPDF.submit=PDF bihurtu
#compress
compress.title=Konprimatu
compress.header=PDFa konprimatu
compress.credit=Zerbitzu honek Ghostscript erabiltzen du PDFak komprimatzeko/optimizatzeko
compress.selectText.1=Eskuz 1etik 4ra
compress.selectText.2=Optimizazio maila:
compress.selectText.3=4 (Izugarria testu-irudietarako)
compress.selectText.4=Automatikoa: automatikoki egokitzen du kalitatea PDFak tamaina doi-doia izan dezan
compress.selectText.5=PDFaren espero den tamaina (adibidez, 25 MB, 10.8 MB, 25 KB)
compress.submit=Konprimatu
#Add image
addImage.title=Gehitu irudia
addImage.header=Gehitu PDF-irudia
addImage.everyPage=Orrialde guztiak?
addImage.upload=Gehitu irudia
addImage.submit=Gehitu irudia
#merge
merge.title=Elkartu
merge.header=Elkartu zenbait PDF (2+)
merge.submit=Elkartu
#pdfOrganiser
pdfOrganiser.title=Orrialdeen antolatzailea
pdfOrganiser.header=PDF orrialdeen antolatzailea
pdfOrganiser.submit=Antolatu orrialdeak
#herramienta multiple
multiTool.title= PDF erabilera anitzeko tresna
multiTool.header=PDF erabilera anitzeko tresna
#pageRemover
pageRemover.title=Orrialdeen ezabatzailea
pageRemover.header=PDF orrialdeen ezabatzailea
pageRemover.pagesToDelete=Ezabatu beharreko orrialdeak (sartu komaz bereizitako orrialde-zenbakien zerrenda):
pageRemover.submit=Ezabatu orrialdeak
#rotate
rotate.title=Biratu PDFa
rotate.header=Biratu PDFa
rotate.SeleccionaAngle=Hautatu errotazio-angelua (90 graduren multiploa):
rotate.submit=Biratu
#merge
split.title=Zatitu PDFa
split.header=Zatitu PDFa
split.desc.1=Hautatzen dituzun zenbakiak zatiketa egin nahi duzun orrialde-zenbakiak dira
split.desc.2=Beraz, 1,3,7-8 hautatzean 10 orrialdeko dokumentua zatituko luke 6 PDF fitxategi bereizituetan
split.desc.3=#1 Dokumentua: 1. orrialdea
split.desc.4=#2 Dokumentua: 2. eta 3. orrialdeak
split.desc.5=#3 Dokumentua: 4., 5. eta 6. orrialdeak
split.desc.6=#4 Dokumentua: 7. orrialdea
split.desc.7=#5 Dokumentua: 8. orrialdea
split.desc.8=#6 Dokumentua: 9. eta 10. orrialdeak
split.splitPages=Sartu orrialdeak zatitzeko:
split.submit=Zatitu
#merge
imageToPDF.title=Irudia PDF bihurtu
imageToPDF.header=Irudia PDF bihurtu
imageToPDF.submit=Bihurtu
imageToPDF.selectText.1=Zabaldu doitzeko
imageToPDF.selectText.2=PDFaren errotazio automatikoa
imageToPDF.selectText.3=Fitxategi askoren logika (gaituta bakarrik zenbait irudirekin ari denean)
imageToPDF.selectText.4=Elkartu PDF bakar batean
imageToPDF.selectText.5=Bihurtu eta PDF bereizituak sortu
#pdfToImage
pdfToImage.title=PDFa irudi bihurtu
pdfToImage.header=PDFa irudi bihurtu
pdfToImage.selectText=Irudi-formatua
pdfToImage.singleOrMultiple=Ondoriozko irudi-mota
pdfToImage.single=Irudi handi bakarra
pdfToImage.multi=Zenbait irudi
pdfToImage.colorType=Kolore-mota
pdfToImage.color=Kolorea
pdfToImage.grey=Gris-eskala
pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!)
pdfToImage.submit=Bihurtu
#addPassword
addPassword.title=Gehitu pasahitza
addPassword.header=Gehitu pasahitza (enkriptatu)
addPassword.selectText.1=Hautatu PDFa enkriptatzeko
addPassword.selectText.2=Pasahitza
addPassword.selectText.3=Gakoaren luzera
addPassword.selectText.4=Balio altuak sendoagoak dira, baina balio baxuek bateragarritasun hobea dute
addPassword.selectText.5=Ezartzeko baimenak
addPassword.selectText.6=Galarazi dokumentuaren mihiztaketa
addPassword.selectText.7=Galarazi edukia ateratzea
addPassword.selectText.8=Galarazi ateratzea irisgarritasunerako
addPassword.selectText.9=Galarazi inprimakia betetzea
addPassword.selectText.10=Galarazi aldaketak egitea
addPassword.selectText.11=Galarazi oharrak aldatzea
addPassword.selectText.12=Galarazi inprimatzea
addPassword.selectText.13=Galarazi zenbait formatu inprimatzea
addPassword.selectText.14=Pasahitza
addPassword.selectText.15=Mugatu zer egin daitekeen dokumentuarekin behin zabalduta (Irakurle guztiek onartu gabe)
addPassword.selectText.16=Mugatu dokumentu bera zabaltzeko aukera
addPassword.submit=Enkriptatu
#watermark
watermark.title=Gehitu ur-marka
watermark.header=Gehitu ur-marka
watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko:
watermark.selectText.2=Ur-markaren testua:
watermark.selectText.3=Letra-tipoaren tamaina:
watermark.selectText.4=Errotazioa (0-360):
watermark.selectText.5=Zabalera (ur-marka bakoitzaren arteko espazioa horizontalean):
watermark.selectText.6=Altuera (ur-marka bakoitzaren arteko espazioa bertikalean):
watermark.selectText.7=Opakutasuna (0% - 100%):
watermark.submit=Gehitu ur-marka
#remove-watermark
remove-watermark.title=Ezabatu ur-marka
remove-watermark.header=Ezabatu ur-marka
remove-watermark.selectText.1=Hautatu PDFa ur-marka ezabatzeko:
remove-watermark.selectText.2=Ur-markaren testua:
remove-watermark.submit=Ezabatu ur-marka
#Change permissions
permissions.title=Aldatu baimenak
permissions.header=Aldatu baimenak
permissions.warning=Oharra: baimen hauek aldatzea ezinezkoa izan dadin, gomendatzen da pasahitz batekin konfiguratzea pasahitza aldatzeko orriaren bitartez
permissions.selectText.1=Hautatu PDFa baimenak aldatzeko
permissions.selectText.2=Baimenak, ezarri beharrekoak
permissions.selectText.3=Galarazi dokumentuaren mihiztaketa
permissions.selectText.4=Galarazi edukia ateratzea
permissions.selectText.5=Galarazi ateratzea irisgarritasunerako
permissions.selectText.6=Galarazi inprimakia betetzea
permissions.selectText.7=Galarazi aldaketak egitea
permissions.selectText.8=Galarazi oharrak aldatzea
permissions.selectText.9=Galarazi inprimatzea
permissions.selectText.10=Galarazi zenbait formatu inprimatzea
permissions.submit=Aldatu
#remove password
removePassword.title=Ezabatu pasahitza
removePassword.header=Ezabatu pasahitza (desenkriptatu)
removePassword.selectText.1=Hautatu PDFa desenkriptatzeko
removePassword.selectText.2=Pasahitza
removePassword.submit=Ezabatu
changeMetadata.title=Aldatu metadatuak
changeMetadata.header=Aldatu metadatuak
changeMetadata.selectText.1=Editatu aldatu nahi dituzun aldagaiak
changeMetadata.selectText.2=Ezabatu metadatu guztiak
changeMetadata.selectText.3=Erakutsi metadatu pertsonalizatuak:
changeMetadata.author=Egilea:
changeMetadata.creationDate=Sortze-data (aaaa/MM/dd HH:mm:ss):
changeMetadata.creator=Sortzailea:
changeMetadata.keywords=Gako-hitzak:
changeMetadata.modDate=Aldatze-data (aaaa/MM/dd HH:mm:ss):
changeMetadata.producer=Ekoizlea:
changeMetadata.subject=Gaia:
changeMetadata.title=Izenburua:
changeMetadata.trapped=Trapped:
changeMetadata.selectText.4=Beste metadatu batzuk:
changeMetadata.selectText.5=Gehitu metadatu pertsonalizatuen sarrera
changeMetadata.submit=Aldatu
xlsToPdf.title=Excela PDF bihurtu
xlsToPdf.header=Excela PDF bihurtu
xlsToPdf.selectText.1=Hautatu Excel XLSren edo XLSXren kalkulu-orria bihurtzeko
xlsToPdf.convert=Bikurtu
pdfToPDFA.title=PDFa PDF/A bihurtu
pdfToPDFA.header=PDFa PDF/A bihurtu
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
pdfToPDFA.submit=Bihurtu
PDFToWord.title=PDFa Word bihurtu
PDFToWord.header=PDFa Word bihurtu
PDFToWord.selectText.1=Irteerako fitxategiaren formatua
PDFToWord.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
PDFToWord.submit=Bihurtu
PDFToPresentation.title=PDFa aurkezpen bihurtu
PDFToPresentation.header=PDFa aurkezpen bihurtu
PDFToPresentation.selectText.1=Irteerako fitxategiaren formatua
PDFToPresentation.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
PDFToPresentation.submit=Bihurtu
PDFToText.title=PDFa TXT/RTF bihurtu
PDFToText.header=PDFa TXT/RTF bihurtu
PDFToText.selectText.1=Irteerako fitxategiaren formatua
PDFToText.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
PDFToText.submit=Bihurtu
PDFToHTML.title=PDFa HTML bihurtu
PDFToHTML.header=PDFa HTML bihurtu
PDFToHTML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
PDFToHTML.submit=Bihurtu
PDFToXML.title=PDFa XML bihurtu
PDFToXML.header=PDFa XML bihurtu
PDFToXML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
PDFToXML.submit=Bihurtu

View File

@@ -24,6 +24,7 @@ close=Fermer
filesSelected=fichiers sélectionnés
noFavourites=Aucun favori ajouté
bored=Ennuyé d'attendre ?
alphabet=Alphabet
#############
# HOME-PAGE #
#############
@@ -127,15 +128,37 @@ home.repair.desc=Essaye de réparer un PDF corrompu/cassé
home.removeBlanks.title=Supprimer les pages vierges
home.removeBlanks.desc=Détecte et supprime les pages vierges d'un document
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.compare.title=Comparer
home.compare.desc=Compare et affiche les différences entre 2 documents PDF
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=Télécharger le PDF
text=Texte
font=Police
selectFilter=-- Sélectionner --
pageNum=numéro de page
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Signature du certificat
certSign.header=Signer un PDF avec votre certificat (Travail en cours)
certSign.selectPDF=Sélectionnez un fichier PDF à signer :
@@ -240,6 +263,7 @@ fileToPDF.submit=Convertir en PDF
addImage.title=Ajouter une image
addImage.header=Ajouter une image au PDF
addImage.everyPage=Chaque page?
addImage.upload=Ajouter une image
addImage.submit=Ajouter une image
#compress
@@ -334,6 +358,9 @@ addPassword.selectText.10=Empêcher la modification
addPassword.selectText.11=Empêcher la modification des annotations
addPassword.selectText.12=Empêcher l'impression
addPassword.selectText.13=Empêcher l'impression de différents formats
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Crypter
#watermark

View File

@@ -20,6 +20,7 @@ close=Chiudi
filesSelected=file selezionati
noFavourites=Nessun preferito
bored=Stanco di aspettare?
alphabet=Alfabeto
#############
# HOME-PAGE #
#############
@@ -122,15 +123,37 @@ home.repair.desc=Prova a riparare un PDF corrotto.
home.removeBlanks.title=Rimuovi pagine vuote
home.removeBlanks.desc=Trova e rimuovi pagine vuote da un PDF.
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.compare.title=Compara
home.compare.desc=Vedi e compara le differenze tra due PDF.
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=Scarica PDF
text=Testo
font=Font
selectFillter=-- Seleziona --
pageNum=Numero pagina
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Firma del certificato
certSign.header=Firma un PDF con il tuo certificato (Lavoro in corso)
certSign.selectPDF=Seleziona un file PDF per la firma:
@@ -248,8 +271,9 @@ compress.submit=Comprimi
#Add image
addImage.title=Aggiungi Immagine
addImage.header=Aggiungi un'immagine ad un PDF.
addImage.header=Aggiungi un'immagine ad un PDF
addImage.everyPage=Ogni pagina?
addImage.upload=Aggiungi immagine
addImage.submit=Aggiungi immagine
@@ -337,6 +361,9 @@ addPassword.selectText.10=Previeni modifiche
addPassword.selectText.11=Previeni annotazioni
addPassword.selectText.12=Previeni stampa
addPassword.selectText.13=Previeni stampa in diversi formati
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Crittografa
#watermark

View File

@@ -0,0 +1,472 @@
###########
# Generic #
###########
# the direction that the language is written (ltr = left to right, rtl = right to left)
language.direction=ltr
pdfPrompt=PDFを選択
multiPdfPrompt=PDFを選択 (2つ以上)
multiPdfDropPrompt=PDFを選択 (又はドラッグ&ドロップ)
imgPrompt=画像を選択
genericSubmit=送信
processTimeWarning=警告:この処理はファイルサイズによって1分程度かかることがあります
pageOrderPrompt=ページ順序 (ページ番号をカンマ区切り又は2n+1のような関数で入力):
goToPage=移動
true=True
false=False
unknown=不明
save=保存
close=閉じる
filesSelected=選択されたファイル
noFavourites=お気に入りはありません
bored=待ち時間が退屈<EFBFBD><EFBFBD>
alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8<43>
#############
# HOME-PAGE #
#############
home.desc=PDFのあらゆるニーズに対応するローカルホスティングされた総合窓口です。
navbar.convert=変換
navbar.security=セキュリティ
navbar.other=その他
navbar.darkmode=ダークモード
navbar.pageOps=ページ操作
home.multiTool.title=PDFマルチツール
home.multiTool.desc=ページの結合、回転、並べ替え、削除します。
home.merge.title=結合
home.merge.desc=複数のPDFを1つに結合します。
home.split.title=分割
home.split.desc=PDFを複数のドキュメントに分割します。
home.rotate.title=回転
home.rotate.desc=PDFを回転します。
home.imageToPdf.title=画像をPDFに変換
home.imageToPdf.desc=画像 (PNG, JPEG, GIF) をPDFに変換します。
home.pdfToImage.title=PDFを画像に変換
home.pdfToImage.desc=PDFを画像 (PNG, JPEG, GIF) に変換します。
home.pdfOrganiser.title=整理
home.pdfOrganiser.desc=ページの削除/並べ替えします。
home.addImage.title=画像の追加
home.addImage.desc=PDF上の任意の場所に画像を追加します。
home.watermark.title=透かしの追加
home.watermark.desc=PDFに独自の透かしを追加します。
home.remove-watermark.title=透かしの削除
home.remove-watermark.desc=PDFから透かしを削除します。
home.permissions.title=権限の変更
home.permissions.desc=PDFの権限を変更します。
home.removePages.title=削除
home.removePages.desc=PDFから不要なページを削除します。
home.addPassword.title=パスワードの追加
home.addPassword.desc=PDFをパスワードで暗号化します。
home.removePassword.title=パスワードの削除
home.removePassword.desc=PDFからパスワードの削除します。
home.compressPdfs.title=圧縮
home.compressPdfs.desc=PDFを圧縮してファイルサイズを小さくします。
home.changeMetadata.title=メタデータの変更
home.changeMetadata.desc=PDFのメタデータを変更/削除/追加します。
home.fileToPDF.title=ファイルをPDFに変換
home.fileToPDF.desc=ほぼすべてのファイルをPDFに変換します。 (DOCX, PNG, XLS, PPT, TXTなど)
home.ocr.title=OCR / クリーンアップ
home.ocr.desc=クリーンアップはPDF内の画像からテキストを検出してテキストとして再追加します。
home.extractImages.title=画像の抽出
home.extractImages.desc=PDFからすべての画像を抽出してzipで保存します。
home.pdfToPDFA.title=PDFをPDF/Aに変換
home.pdfToPDFA.desc=長期保存のためにPDFをPDF/Aに変換。
home.PDFToWord.title=PDFをWordに変換
home.PDFToWord.desc=PDFをWord形式に変換します。 (DOC, DOCX および ODT)
home.PDFToPresentation.title=PDFをプレゼンテーションに変換
home.PDFToPresentation.desc=PDFをプレゼンテーション形式に変換します。 (PPT, PPTX および ODP)
home.PDFToText.title=PDFをText/RTFに変換
home.PDFToText.desc=PDFをTextまたはRTF形式に変換します。
home.PDFToHTML.title=PDFをHTMLに変換
home.PDFToHTML.desc=PDFをHTML形式に変換します。
home.PDFToXML.title=PDFをXMLに変換
home.PDFToXML.desc=PDFをXML形式に変換します。
home.ScannerImageSplit.title=スキャンされた画像の検出/分割
home.ScannerImageSplit.desc=1枚の画像/PDFから複数の写真を分割します。
home.sign.title=署名
home.sign.desc=手書き、テキストまたは画像によってPDFに署名を追加します。
home.flatten.title=平坦化
home.flatten.desc=PDFからインタラクティブな要素とフォームをすべて削除します。
home.repair.title=修復
home.repair.desc=破損したPDFの修復を試みます。
home.removeBlanks.title=空白ページの削除
home.removeBlanks.desc=ドキュメントから空白ページを検出して削除します。
home.compare.title=比較
home.compare.desc=2つのPDFを比較して表示します。
home.certSign.title=証明書による署名
home.certSign.desc=証明書/キーを使用してPDFに署名します。 (PEM/P12)
home.pageLayout.title=マルチページレイアウト
home.pageLayout.desc=PDFの複数のページを1ページに結合します。
home.scalePages.title=ページの縮尺の調整
home.scalePages.desc=ページやコンテンツの縮尺を変更します。
error.pdfPassword=PDFにパスワードが設定されてますが、パスワードが入力されてないか間違ってます。
downloadPdf=PDFをダウンロード
text=テキスト
font=フォント
selectFillter=-- 選択 --
pageNum=ページ番号
pageLayout.title=マルチページレイアウト
pageLayout.header=マルチページレイアウト
pageLayout.pagesPerSheet=1枚あたりのページ数:
pageLayout.submit=送信
scalePages.title=ページの縮尺の調整
scalePages.header=ページの縮尺の調整
scalePages.pageSize=1ページのサイズ
scalePages.scaleFactor=1ページの拡大レベル (トリミング)。
scalePages.submit=送信
certSign.title=証明書による署名
certSign.header=証明書を使用してPDFに署名します。 (進行中)
certSign.selectPDF=署名するPDFファイルを選択:
certSign.selectKey=秘密キーファイルを選択 (PKCS#8形式、.pemまたは.der) :
certSign.selectCert=証明書ファイルを選択 (X.509形式、.pemまたは.der) :
certSign.selectP12=PKCS#12キーストアファイルを選択 (.p12または.pfx) (オプション。指定する場合は秘密キーと証明書が含まれている必要があります。):
certSign.certType=証明書の種類
certSign.password=キーストアまたは秘密キーのパスワードを入力 (ある場合) :
certSign.showSig=署名を表示
certSign.reason=理由
certSign.location=場所
certSign.name=名前
certSign.submit=PDFに署名
removeBlanks.title=空白の削除
removeBlanks.header=空白ページの削除
removeBlanks.threshold=しきい値 :
removeBlanks.thresholdDesc=白色ピクセルの白さを決めるためのしきい値
removeBlanks.whitePercent=白比率
removeBlanks.whitePercentDesc=削除するページの白の割合
removeBlanks.submit=空白ページの削除
compare.title=比較
compare.header=PDFの比較
compare.document.1=ドキュメント 1
compare.document.2=ドキュメント 2
compare.submit=比較
sign.title=署名
sign.header=PDFに署名
sign.upload=画像をアップロード
sign.draw=署名を書く
sign.text=テキスト入力
sign.clear=クリア
sign.add=追加
repair.title=修復
repair.header=PDFを修復
repair.submit=修復
flatten.title=平坦化
flatten.header=PDFを平坦化する
flatten.submit=平坦化
ScannerImageSplit.selectText.1=角度のしきい値:
ScannerImageSplit.selectText.2=画像を回転させるために必要な絶対角度の最小値を設定 (初期値:10)。
ScannerImageSplit.selectText.3=許容範囲:
ScannerImageSplit.selectText.4=推定された背景色周辺のカラーバリエーションの範囲を決定 (初期値:30)。
ScannerImageSplit.selectText.5=最小面積:
ScannerImageSplit.selectText.6=画像の最小面積のしきい値を設定 (初期値:10000)。
ScannerImageSplit.selectText.7=最小輪郭面積:
ScannerImageSplit.selectText.8=画像の最小の輪郭面積のしきい値を設定。
ScannerImageSplit.selectText.9=境界線サイズ:
ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。
navbar.settings=設定
settings.title=設定
settings.update=利用可能なアップデート
settings.appVersion=Appバージョン:
settings.downloadOption.title=ダウンロードオプション (zip以外の単一ファイル):
settings.downloadOption.1=同じウィンドウで開く
settings.downloadOption.2=新しいウィンドウで開く
settings.downloadOption.3=ファイルをダウンロード
settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する
#OCR
ocr.title=OCR / クリーンアップ
ocr.header=クリーンアップ / OCR (光学式文字認識)
ocr.selectText.1=PDF内で検出される言語を選択 (リストされているものは現在検出されているものです):
ocr.selectText.2=OCR処理されたPDFと一緒に、OCRしたテキストを含むテキストファイルを作成する
ocr.selectText.3=斜めにスキャンされたページを回転させて修正する
ocr.selectText.4=ページをきれいにして背景ノイズの中からテキストを検出しにくくする。(出力は変わりません)
ocr.selectText.5=ページをきれいにして背景ノイズの中からテキストを検出しにくくし、出力はクリーンアップを維持する。
ocr.selectText.6=インタラクティブなテキストを含むページを無視し、画像ページのみをOCRする
ocr.selectText.7=強制OCR、全てのページで元のテキスト要素を全て削除してOCRする
ocr.selectText.8=Normal (PDFにテキストが含まれている場合はエラーになります。)
ocr.selectText.9=追加設定
ocr.selectText.10=OCRモード
ocr.selectText.11=OCR後に画像を削除する (すべての画像を削除します。変換ステップの一部である場合にのみ有効です)。
ocr.selectText.12=レンダリングタイプ (高度)
ocr.help=他の言語でこれを使用する方法やDocker以外で使用する方法についてはこのドキュメントをお読みください。
ocr.credit=本サービスにはOCRにOCRmyPDFとTesseractを使用しています。
ocr.submit=OCRでPDFを処理する
extractImages.title=画像の抽出
extractImages.header=画像の抽出
extractImages.selectText=抽出した画像のフォーマットを選択
extractImages.submit=抽出
#File to PDF
fileToPDF.title=ファイルをPDFに変換
fileToPDF.header=あらゆるファイルをPDFに変換
fileToPDF.credit=本サービスはファイル変換にLibreOfficeとUnoconvを使用しています。
fileToPDF.supportedFileTypes=サポートされるファイル形式には以下が含まれますが、完全な更新リストについてはLibreOfficeのドキュメントを参照してください。
fileToPDF.submit=PDFを変換
#compress
compress.title=圧縮
compress.header=PDFを圧縮
compress.credit=本サービスはPDFの圧縮/最適化にGhostscriptを使用しています。
compress.selectText.1=手動モード - 1 から 4
compress.selectText.2=品質レベル:
compress.selectText.3=4 (テキスト画像は最悪)
compress.selectText.4=自動モード - PDFを正確なサイズにするために品質を自動調整する。
compress.selectText.5=PDFサイズ (例 25MB, 10.8MB, 25KB)
compress.submit=圧縮
#Add image
addImage.title=画像の追加
addImage.header=PDFに画像を追加
addImage.everyPage=全ページ?
addImage.upload=画像の追加
addImage.submit=画像の追加
#merge
merge.title=結合
merge.header=複数のPDFを結合 (2ファイル以上)
merge.submit=結合
#pdfOrganiser
pdfOrganiser.title=整理
pdfOrganiser.header=PDFページの整理
pdfOrganiser.submit=ページの整理
#multiTool
multiTool.title=PDFマルチツール
multiTool.header=PDFマルチツール
#pageRemover
pageRemover.title=ページ削除
pageRemover.header=PDFページ削除
pageRemover.pagesToDelete=削除するページ (ページ番号のカンマ区切りリストを入力してください):
pageRemover.submit=ページ削除
#rotate
rotate.title=PDFの回転
rotate.header=PDFの回転
rotate.selectAngle=回転角度を選択 (90度の倍数):
rotate.submit=回転
#merge
split.title=PDFの分割
split.header=PDFの分割
split.desc.1=選択する番号は分割するページ番号です。
split.desc.2=したがって、1,3,7-8を選択すると、10ページのドキュメントが以下のように6つのPDFに分割されることになります。
split.desc.3=ドキュメント #1: ページ 1
split.desc.4=ドキュメント #2: ページ 2, 3
split.desc.5=ドキュメント #3: ページ 4, 5, 6
split.desc.6=ドキュメント #4: ページ 7
split.desc.7=ドキュメント #5: ページ 8
split.desc.8=ドキュメント #6: ページ 9, 10
split.splitPages=分割するページ番号を入力:
split.submit=分割
#merge
imageToPDF.title=画像をPDFに変換
imageToPDF.header=画像をPDFに変換
imageToPDF.submit=変換
imageToPDF.selectText.1=フィットするように引き伸ばす
imageToPDF.selectText.2=PDFの自動回転
imageToPDF.selectText.3=マルチファイルの処理 (複数の画像を操作する場合に有効になります)
imageToPDF.selectText.4=1つのPDFに結合
imageToPDF.selectText.5=個別のPDFに変換
#pdfToImage
pdfToImage.title=PDFを画像に変換
pdfToImage.header=PDFを画像に変換
pdfToImage.selectText=画像の形式
pdfToImage.singleOrMultiple=画像出力タイプ
pdfToImage.single=単一の大きな画像
pdfToImage.multi=複数の画像
pdfToImage.colorType=カラーモード
pdfToImage.color=カラー
pdfToImage.grey=グレースケール
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
pdfToImage.submit=変換
#addPassword
addPassword.title=パスワードの追加
addPassword.header=パスワードの追加 (暗号化)
addPassword.selectText.1=暗号化するPDFを選択
addPassword.selectText.2=ユーザーパスワード
addPassword.selectText.3=暗号化キーの長さ
addPassword.selectText.4=値が大きいほど強力ですが、値が小さいほど互換性が高くなります。
addPassword.selectText.5=権限の設定 (所有者パスワードとの併用をおすすめします)
addPassword.selectText.6=ドキュメントの組立を禁止
addPassword.selectText.7=コンテンツの抽出を禁止
addPassword.selectText.8=アクセシビリティのための抽出を禁止
addPassword.selectText.9=フォームへの入力を禁止
addPassword.selectText.10=変更を禁止
addPassword.selectText.11=注釈の変更を禁止
addPassword.selectText.12=印刷を禁止
addPassword.selectText.13=異なる形式の印刷を禁止
addPassword.selectText.14=所有者パスワード
addPassword.selectText.15=ドキュメントを開いた後に実行できる操作を制限します (すべてのリーダーでサポートされているわけではありません)
addPassword.selectText.16=ドキュメントを開くことを制限します
addPassword.submit=暗号化
#watermark
watermark.title=透かしの追加
watermark.header=透かしの追加
watermark.selectText.1=透かしを追加するPDFを選択:
watermark.selectText.2=透かしのテキスト:
watermark.selectText.3=文字サイズ:
watermark.selectText.4=回転 (0-360):
watermark.selectText.5=幅スペース (各透かし間の水平方向のスペース):
watermark.selectText.6=高さスペース (各透かし間の垂直方向のスペース):
watermark.selectText.7=不透明度 (0% - 100%):
watermark.submit=透かしを追加
#remove-watermark
remove-watermark.title=透かしの削除
remove-watermark.header=透かしの削除
remove-watermark.selectText.1=透かしを削除するPDFを選択:
remove-watermark.selectText.2=透かしのテキスト:
remove-watermark.submit=透かしを削除
#Change permissions
permissions.title=権限の変更
permissions.header=権限の変更
permissions.warning=警告、これらの権限を変更できないようにするため、パスワードの追加ページでパスワードを設定することを推奨します。
permissions.selectText.1=権限を変更するPDFを選択
permissions.selectText.2=権限の設定
permissions.selectText.3=ドキュメントの組立を禁止
permissions.selectText.4=コンテンツの抽出を禁止
permissions.selectText.5=アクセシビリティのための抽出を禁止
permissions.selectText.6=フォームへの入力を禁止
permissions.selectText.7=変更を禁止
permissions.selectText.8=注釈の変更を禁止
permissions.selectText.9=印刷を禁止
permissions.selectText.10=異なる形式の印刷を禁止
permissions.submit=変更
#remove password
removePassword.title=パスワードの削除
removePassword.header=パスワードの削除 (復号化)
removePassword.selectText.1=復号化するPDFを選択
removePassword.selectText.2=パスワード
removePassword.submit=削除
changeMetadata.title=メタデータの変更
changeMetadata.header=メタデータの変更
changeMetadata.selectText.1=変更したい変数を編集してください
changeMetadata.selectText.2=すべてのメタデータを削除
changeMetadata.selectText.3=カスタムメタデータを表示
changeMetadata.author=著者:
changeMetadata.creationDate=作成日 (yyyy/MM/dd HH:mm:ss):
changeMetadata.creator=作成者:
changeMetadata.keywords=キーワード:
changeMetadata.modDate=変更日 (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=プロデューサー:
changeMetadata.subject=主題:
changeMetadata.title=タイトル:
changeMetadata.trapped=トラッピング:
changeMetadata.selectText.4=その他のメタデータ:
changeMetadata.selectText.5=カスタムメタデータの追加
changeMetadata.submit=変更
xlsToPdf.title=ExcelをPDFに変換
xlsToPdf.header=ExcelをPDFに変換
xlsToPdf.selectText.1=変換するXLSまたはXLSX Execlシートを選択
xlsToPdf.convert=変換
pdfToPDFA.title=PDFをPDF/Aに変換
pdfToPDFA.header=PDFをPDF/Aに変換
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。
pdfToPDFA.submit=変換
PDFToWord.title=PDFをWordに変換
PDFToWord.header=PDFをWordに変換
PDFToWord.selectText.1=出力ファイル形式
PDFToWord.credit=本サービスはファイル変換にLibreOfficeを使用しています。
PDFToWord.submit=変換
PDFToPresentation.title=PDFをプレゼンテーションに変換
PDFToPresentation.header=PDFをプレゼンテーションに変換
PDFToPresentation.selectText.1=出力ファイル形式
PDFToPresentation.credit=本サービスはファイル変換にLibreOfficeを使用しています。
PDFToPresentation.submit=変換
PDFToText.title=PDFをText/RTFに変換
PDFToText.header=PDFをText/RTFに変換
PDFToText.selectText.1=出力ファイル形式
PDFToText.credit=本サービスはファイル変換にLibreOfficeを使用しています。
PDFToText.submit=変換
PDFToHTML.title=PDFをHTMLに変換
PDFToHTML.header=PDFをHTMLに変換
PDFToHTML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
PDFToHTML.submit=変換
PDFToXML.title=PDFをXMLに変換
PDFToXML.header=PDFをXMLに変換
PDFToXML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
PDFToXML.submit=変換

View File

@@ -20,6 +20,7 @@ close=닫기
filesSelected=개 파일 선택됨
noFavourites=즐겨찾기 없음
bored=기다리는 게 지루하신가요?
alphabet=\uC54C\uD30C\uBCB3
#############
# HOME-PAGE #
#############
@@ -128,6 +129,13 @@ home.compare.desc=2개의 PDF 문서를 비교하고 차이를 표시합니다.
home.certSign.title=인증서로 서명
home.certSign.desc=PDF에 인증서/키로 서명합니다. (PEM/P12)
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=PDF 다운로드
text=텍스트
@@ -135,6 +143,17 @@ font=폰트
selectFillter=-- 선택 --
pageNum=페이지 번호
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=인증서로 서명
certSign.header=PDF에 당신의 인증서로 서명하세요 (개발 중)
certSign.selectPDF=서명할 PDF를 선택하세요:
@@ -258,6 +277,7 @@ compress.submit=압축
addImage.title=이미지 추가
addImage.header=PDF에 이미지 추가
addImage.everyPage=모든 페이지에 적용
addImage.upload=이미지 추가
addImage.submit=이미지 추가
@@ -368,7 +388,10 @@ addPassword.selectText.9=양식 작성 방지
addPassword.selectText.10=수정 방지
addPassword.selectText.11=주석 수정 방지
addPassword.selectText.12=인쇄 방지
addPassword.selectText.13=다른 형식으로 인쇄 방
addPassword.selectText.13=다른 형식으로 인쇄 방<EFBFBD>
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself<6C>
addPassword.submit=암호화
#watermark

View File

@@ -12,14 +12,15 @@ genericSubmit=Wyślij
processTimeWarning=Ostrzeżenie: Ten proces może potrwać do minuty, w zależności od rozmiaru pliku
pageOrderPrompt=Kolejność stron (wprowadź listę numerów stron oddzielonych przecinkami) :
goToPage=Idź
true=Prawda
false=Fałsz
true=Tak
false=Nie
unknown=Nieznany
save=Zapisz
close=Zamknij
filesSelected=wybrane pliki
noFavourites=Nie dodano ulubionych
bored=Znudzony czekaniem?
alphabet=Alfabet
#############
# HOME-PAGE #
#############
@@ -54,7 +55,7 @@ home.pdfOrganiser.title=Uporządkuj
home.pdfOrganiser.desc=Usuń/Zmień kolejność stron w dowolnej kolejności
home.addImage.title=Dodaj obraz
home.addImage.desc=Dodaje obraz w wybranym miejscu w dokumencie PDF (komponent w budowie)
home.addImage.desc=Dodaje obraz w wybranym miejscu w dokumencie PDF (moduł w budowie)
home.watermark.title=Dodaj znak wodny
home.watermark.desc=Dodaj niestandardowy znak wodny do dokumentu PDF.
@@ -80,14 +81,14 @@ home.compressPdfs.desc=Kompresuj dokumenty PDF, aby zmniejszyć ich rozmiar.
home.changeMetadata.title=Zmień metadane
home.changeMetadata.desc=Zmień/Usuń/Dodaj metadane w dokumencie PDF
home.fileToPDF.title=Konwertuj plik do dokumentu PDF
home.fileToPDF.desc=Konwertuj prawie każdy plik do dokumentu PDF (DOCX, PNG, XLS, PPT, TXT i więcej)
home.fileToPDF.title=Konwertuj plik do PDF
home.fileToPDF.desc=Konwertuj dowolny plik do dokumentu PDF (DOCX, PNG, XLS, PPT, TXT i więcej)
home.ocr.title=OCR / Zamiana na tekst
home.ocr.desc=OCR skanuje i wykrywa tekst z obrazów w dokumencie PDF i zamienia go na tekst.
home.extractImages.title=Wyodrębnij obrazy
home.extractImages.desc=Wyodrębnia wszystkie obrazy z dokumentu PDF i zapisuje je w formacie zip
home.extractImages.desc=Wyodrębnia wszystkie obrazy z dokumentu PDF i zapisuje je w wybranym formacie
home.pdfToPDFA.title=PDF na PDF/A
home.pdfToPDFA.desc=Konwertuj dokument PDF na PDF/A w celu długoterminowego przechowywania
@@ -123,10 +124,18 @@ home.removeBlanks.title=Usuń puste strony
home.removeBlanks.desc=Wykrywa i usuwa puste strony z dokumentu PDF
home.compare.title=Porównaj
home.compare.desc=Porównuje i pokazuje różnice między 2 dokumentami PDF
home.compare.desc=Porównuje i pokazuje różnice między dwoma dokumentami PDF
home.certSign.title=Podpisz certyfikatem osobistym
home.certSign.desc=Podpisz dokument PDF za pomocą certyfikatu/klucza osobistego (PEM/P12)
home.certSign.title=Podpisz certyfikatem
home.certSign.desc=Podpisz dokument PDF za pomocą certyfikatu/klucza prywatnego (PEM/P12)
home.pageLayout.title=Układ wielu stron
home.pageLayout.desc=Scal wiele stron dokumentu PDF w jedną stronę
home.scalePages.title=Dopasuj rozmiar stron
home.scalePages.desc=Dopasuj rozmiar stron wybranego dokumentu PDF
error.pdfPassword=Dokument PDF jest zabezpieczony hasłem, musisz podać prawidłowe hasło.
downloadPdf=Pobierz PDF
text=Tekst
@@ -134,16 +143,27 @@ font=Czcionka
selectFillter=-- Wybierz --
pageNum=Numer strony
pageLayout.title=Układ wielu stron
pageLayout.header=Układ wielu stron
pageLayout.pagesPerSheet=Stron na jednym arkuszu:
pageLayout.submit=Wykonaj
scalePages.title=Dopasuj rozmiar stron
scalePages.header=Dopasuj rozmiar stron
scalePages.pageSize=Rozmiar stron dokumentu:
scalePages.scaleFactor=Poziom powiększenia (przycięcia) stron:
scalePages.submit=Wykonaj
certSign.title=Podpisywanie certyfikatem
certSign.header=Podpisz dokument PDF certyfikatem osobistym (prace w toku)
certSign.header=Podpisz dokument PDF certyfikatem prywatnym (moduł w budowie)
certSign.selectPDF=Wybierz dokument PDF do podpisania:
certSign.selectKey=Wybierz plik klucza prywatnego (format PKCS#8, może to być .pem lub .der):
certSign.selectCert=Wybierz plik certyfikatu (format X.509, może to być .pem lub .der):
certSign.selectP12=Wybierz plik magazynu kluczy PKCS#12 (.p12 lub .pfx) (opcjonalnie, jeśli jest podany, powinien zawierać klucz prywatny i certyfikat):
certSign.certType=Typ certyfikatu
certSign.password=Wprowadź hasło do magazynu kluczy lub klucza prywatnego (jeśli istnieje):
certSign.showSig=Pokaż podpis
certSign.reason=Powód
certSign.showSig=Wyświetl podpis
certSign.reason=Organizacja
certSign.location=Lokalizacja
certSign.name=Nazwa
certSign.submit=Podpisz PDF
@@ -226,13 +246,13 @@ ocr.submit=Przetwarzaj PDF za pomocą OCR
extractImages.title=Wyodrębnij obrazy
extractImages.header=Wyodrębnij obrazy
extractImages.selectText=Wybierz format obrazu, aby je przekonwertować
extractImages.selectText=Wybierz format obrazu, na który chcesz przekonwertować wyodrębniony obraz.
extractImages.submit=Wyodrębnij
#File to PDF
fileToPDF.title=Plik na PDF
fileToPDF.header=Konwertuj kady plik na dokument PDF
fileToPDF.header=Konwertuj dowolny plik na dokument PDF
fileToPDF.credit=Ta usługa używa LibreOffice i Unoconv do konwersji plików.
fileToPDF.supportedFileTypes=Obsługiwane typy plików powinny być zgodne z poniższymi, jednak pełną zaktualizowaną listę obsługiwanych formatów można znaleźć w dokumentacji LibreOffice
fileToPDF.submit=Konwertuj na PDF
@@ -253,6 +273,7 @@ compress.submit=Kompresuj
addImage.title=Dodaj obraz
addImage.header=Dodaj obraz do PDF
addImage.everyPage=Każda strona?
addImage.upload=Dodaj obraz
addImage.submit=Dodaj obraz
@@ -340,6 +361,9 @@ addPassword.selectText.10=Zablokuj modyfikacje
addPassword.selectText.11=Zablokuj modyfikacje adnotacji
addPassword.selectText.12=Zablokuj drukowanie
addPassword.selectText.13=Zablokuj drukowanie różnych formatów
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Zablokuj
#watermark
@@ -349,8 +373,8 @@ watermark.selectText.1=Wybierz dokument PDF, do którego chcesz dodać znak wodn
watermark.selectText.2=Treść znaku wodnego:
watermark.selectText.3=Rozmiar czcionki:
watermark.selectText.4=Obrót (0-360):
watermark.selectText.5=odstępy poziomo (odstęp między każdym znakiem wodnym w poziomie):
watermark.selectText.6=odstępy pionowo (odstęp między każdym znakiem wodnym w pionie):
watermark.selectText.5=Odstęp w poziomie (odstęp między każdym znakiem wodnym w poziomie):
watermark.selectText.6=Odstęp w pionie (odstęp między każdym znakiem wodnym w pionie):
watermark.selectText.7=Nieprzezroczystość (0% - 100%):
watermark.submit=Dodaj znak wodny
@@ -390,14 +414,14 @@ changeMetadata.selectText.1=Edytuj zmienne, które chcesz zmienić
changeMetadata.selectText.2=Usuń wszystkie metadane
changeMetadata.selectText.3=Pokaż niestandardowe metadane:
changeMetadata.author=Autor:
changeMetadata.creationDate=Data utworzenia (dd/MM/yyyy HH:mm:ss):
changeMetadata.creationDate=Data utworzenia (yyyy/MM/dd HH:mm:ss):
changeMetadata.creator=Twórca:
changeMetadata.keywords=Słowa kluczowe:
changeMetadata.modDate=Data modyfikacji (dd/MM/yyyy HH:mm:ss):
changeMetadata.modDate=Data modyfikacji (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=Producent:
changeMetadata.subject=Temat:
changeMetadata.title=Tytuł:
changeMetadata.trapped=Uwięziony:
changeMetadata.trapped=Zablokowany:
changeMetadata.selectText.4=Inne metadane:
changeMetadata.selectText.5=Dodaj niestandardowy wpis w metadanych
changeMetadata.submit=Zmień

View File

@@ -0,0 +1,488 @@
###########
# Generic #
###########
# the direction that the language is written (ltr =esquerda para a direita, rtl = direita para a esquerda)
language.direction=ltr
pdfPrompt=Selecione PDF(s)
multiPdfPrompt=Selecione PDFs (2+)
multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs necessários
imgPrompt=Selecione a(s) imagem(ns)
genericSubmit=Enviar
processTimeWarning=Aviso: esse processo pode levar até um minuto, dependendo do tamanho do arquivo
pageOrderPrompt=Ordem das páginas (digite uma lista separada por vírgulas de números de página):
goToPage=Ir
true=Verdadeiro
false=Falso
unknown=Desconhecido
save=Salvar
close=Fechar
filesSelected=arquivos selecionados
noFavourites=Nenhum favorito adicionado
bored=Entediado esperando?
alphabet=Alfabeto
#############
# HOME-PAGE #
#############
home.desc=Seu melhor utilitário para as necessidades de PDF.
navbar.convert=Converter
navbar.security=Segurança
navbar.other=Outro
navbar.darkmode=Modo Escuro
navbar.pageOps=Operações de página
home.multiTool.title=Multiferramenta de PDF
home.multiTool.desc=Mesclar, girar, reorganizar e remover páginas
home.merge.title=mesclar
home.merge.desc=Mescle facilmente vários PDFs em um.
home.split.title=Dividir
home.split.desc=Dividir PDFs em vários documentos
home.rotate.title=Girar
home.rotate.desc=Gire facilmente seus PDFs.
home.imageToPdf.title=Imagem para PDF
home.imageToPdf.desc=Converta uma imagem (PNG, JPEG, GIF) em PDF.
home.pdfToImage.title=PDF para imagem
home.pdfToImage.desc=Converta um PDF em uma imagem. (PNG, JPG, GIF)
home.pdfOrganiser.title=Organizar
home.pdfOrganiser.desc=Remova/reorganize as páginas em qualquer ordem
home.addImage.title=Adicionar imagem
home.addImage.desc=Adiciona uma imagem em um local definido no PDF (trabalho em andamento)
home.watermark.title=Adicione uma Marca d'água
home.watermark.desc=Adicione uma marca d'água personalizada ao seu documento PDF.
home.remove-watermark.title=Remover marca d'água
home.remove-watermark.desc=Remova marcas d'água do seu documento PDF.
home.permissions.title=Alterar permissões
home.permissions.desc=Altere as permissões do seu documento PDF
home.removePages.title=Remover
home.removePages.desc=Exclua as páginas indesejadas do seu documento PDF.
home.addPassword.title=Adicionar senha
home.addPassword.desc=Criptografe seu documento PDF com uma senha.
home.removePassword.title=Remover senha
home.removePassword.desc=Remova a proteção por senha do seu documento PDF.
home.compressPdfs.title=Comprimir
home.compressPdfs.desc=Comprima PDFs para reduzir o tamanho do arquivo.
home.changeMetadata.title=Alterar metadados
home.changeMetadata.desc=Alterar/remover/adicionar metadados de um documento PDF
home.fileToPDF.title=Converter arquivo para PDF
home.fileToPDF.desc=Converta praticamente qualquer arquivo em PDF (DOCX, PNG, XLS, PPT, TXT e mais)
home.ocr.title=OCR / Varreduras de limpeza
home.ocr.desc=A limpeza verifica e detecta texto de imagens em um PDF e o adiciona novamente como texto.
home.extractImages.title=Extrair imagens
home.extractImages.desc=Extrai todas as imagens de um PDF e as salva em zip
home.pdfToPDFA.title=PDF para PDF/A
home.pdfToPDFA.desc=Converta PDF para PDF/A para armazenamento de longo prazo
home.PDFToWord.title=PDF para Word
home.PDFToWord.desc=Converter PDF para formatos Word (DOC, DOCX e ODT)
home.PDFToPresentation.title=PDF para apresentação
home.PDFToPresentation.desc=Converter PDF para formatos de apresentação (PPT, PPTX e ODP)
home.PDFToText.title=PDF para Texto/RTF
home.PDFToText.desc=Converter PDF em formato de texto ou RTF
home.PDFToHTML.title=PDF para HTML
home.PDFToHTML.desc=Converter PDF para o formato HTML
home.PDFToXML.title=PDF para XML
home.PDFToXML.desc=Converter PDF para o formato XML
home.ScannerImageSplit.title=Detectar/dividir fotos digitalizadas
home.ScannerImageSplit.desc=Divide várias fotos de dentro de uma foto/PDF
home.sign.title=Sinal
home.sign.desc=Adiciona assinatura ao PDF por desenho, texto ou imagem
home.flatten.title=achatar
home.flatten.desc=Remova todos os elementos e formulários interativos de um PDF
home.repair.title=Reparar
home.repair.desc=Tenta reparar um PDF corrompido/quebrado
home.removeBlanks.title=Remover páginas em branco
home.removeBlanks.desc=Detecta e remove páginas em branco de um documento
home.compare.title=Comparar
home.compare.desc=Compara e mostra as diferenças entre 2 documentos PDF
home.certSign.title=Assinar com certificado
home.certSign.desc=Assina um PDF com um Certificado/Chave (PEM/P12)
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=baixar PDF
text=Texto
font=Fonte
selectFillter=-- Selecione --
pageNum=Número de página
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Assinatura de certificado
certSign.header=Assine um PDF com seu certificado (Trabalho em andamento)
certSign.selectPDF=Selecione um arquivo PDF para assinatura:
certSign.selectKey=Selecione seu arquivo de chave privada (formato PKCS#8, pode ser .pem ou .der):
certSign.selectCert=Selecione seu arquivo de certificado (formato X.509, pode ser .pem ou .der):
certSign.selectP12=Selecione seu arquivo de armazenamento de chave PKCS#12 (.p12 ou .pfx) (opcional, se fornecido, deve conter sua chave privada e certificado):
certSign.certType=tipo de certificado
certSign.password=Digite seu armazenamento de chave ou senha de chave privada (se houver):
certSign.showSig=Mostrar assinatura
certSign.reason=Razão
certSign.location=Localização
certSign.name=Nome
certSign.submit=Assinar PDF
removeBlanks.title=Remover espaços em branco
removeBlanks.header=Remover páginas em branco
removeBlanks.threshold=Limite:
removeBlanks.thresholdDesc=Limiar para determinar quão branco um pixel branco deve ser
removeBlanks.whitePercent=Porcentagem branca (%):
removeBlanks.whitePercentDesc=Porcentagem da página que deve ser branca para ser removida
removeBlanks.submit=Remover espaços em branco
compare.title=Comparar
compare.header=Comparar PDFs
compare.document.1=Documento 1
compare.document.2=Documento 2
compare.submit=Comparar
sign.title=Sinal
sign.header=Assinar PDFs
sign.upload=Enviar Imagem
sign.draw=Desenhar Assinatura
sign.text=Entrada de texto
sign.clear=Claro
sign.add=Adicionar
repair.title=Reparar
repair.header=Reparar PDFs
repair.submit=Reparar
flatten.title=achatar
flatten.header=Achatar PDFs
flatten.submit=achatar
ScannerImageSplit.selectText.1=Limite de Ângulo:
ScannerImageSplit.selectText.2=Define o ângulo absoluto mínimo necessário para que a imagem seja girada (padrão: 10).
ScannerImageSplit.selectText.3=Tolerância:
ScannerImageSplit.selectText.4=Determina o intervalo de variação de cor em torno da cor de fundo estimada (padrão: 30).
ScannerImageSplit.selectText.5=Área Mínima:
ScannerImageSplit.selectText.6=Define o limite mínimo de área para uma foto (padrão: 10000).
ScannerImageSplit.selectText.7=Área mínima de contorno:
ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto
ScannerImageSplit.selectText.9=Tamanho da Borda:
ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida para evitar bordas brancas na saída (padrão: 1).
navbar.settings=Configurações
settings.title=Configurações
settings.update=Atualização disponível
settings.appVersion=Versão do aplicativo:
settings.downloadOption.title=Escolha a opção de download (para downloads não compactados de arquivo único):
settings.downloadOption.1=Abrir na mesma janela
settings.downloadOption.2=Abrir em nova janela
settings.downloadOption.3=⇬ Fazer download do arquivo
settings.zipThreshold=Compactar arquivos quando o número de arquivos baixados exceder
#OCR
ocr.title=OCR / Limpeza de digitalização
ocr.header=Varreduras de limpeza / OCR (reconhecimento óptico de caracteres)
ocr.selectText.1=Selecione os idiomas que devem ser detectados no PDF (os listados são os atualmente detectados):
ocr.selectText.2=Produzir arquivo de texto contendo texto OCR ao lado do PDF com OCR
ocr.selectText.3=As páginas corretas foram digitalizadas em um ângulo inclinado girando-as de volta ao lugar
ocr.selectText.4=Limpe a página para que seja menos provável que o OCR encontre o texto no ruído de fundo. (Sem mudança de saída)
ocr.selectText.5=Limpe a página para que seja menos provável que o OCR encontre texto no ruído de fundo, mantendo a limpeza na saída.
ocr.selectText.6=Ignora as páginas que contêm texto interativo, apenas as páginas de OCR que são imagens
ocr.selectText.7=Forçar OCR, irá OCR Todas as páginas removendo todos os elementos de texto originais
ocr.selectText.8=Normal (será um erro se o PDF contiver texto)
ocr.selectText.9=Configurações adicionais
ocr.selectText.10=Modo OCR
ocr.selectText.11=Remova as imagens após o OCR (remove TODAS as imagens, útil apenas se fizer parte da etapa de conversão)
ocr.selectText.12=Tipo de renderização (avançado)
ocr.help=Por favor, leia esta documentação sobre como usar isso para outros idiomas e/ou não usar no docker
ocr.credit=Este serviço usa OCRmyPDF e Tesseract para OCR.
ocr.submit=Processar PDF com OCR
extractImages.title=Extrair Imagens
extractImages.header=Extrair Imagens
extractImages.selectText=Selecione o formato de imagem para converter as imagens extraídas em
extractImages.submit=Extrair
#File to PDF
fileToPDF.title=Arquivo para PDF
fileToPDF.header=Converta qualquer arquivo para PDF
fileToPDF.credit=Este serviço usa LibreOffice e Unoconv para conversão de arquivos.
fileToPDF.supportedFileTypes=Os tipos de arquivo suportados devem incluir o abaixo, no entanto, para obter uma lista atualizada completa de formatos suportados, consulte a documentação do LibreOffice
fileToPDF.submit=Converter para PDF
#compress
compress.title=Comprimir
compress.header=Comprimir PDF
compress.credit=Este serviço usa o Ghostscript para compressão/otimização de PDF.
compress.selectText.1=Modo Manual - De 1 a 4
compress.selectText.2=Nível de otimização:
compress.selectText.3=4 (Péssimo para imagens de texto)
compress.selectText.4=Modo automático - Auto ajusta a qualidade para obter o tamanho exato do PDF
compress.selectText.5=Tamanho esperado do PDF (por exemplo, 25 MB, 10,8 MB, 25 KB)
compress.submit=Comprimir
#Add image
addImage.title=Adicionar imagem
addImage.header=Adicionar imagem ao PDF
addImage.everyPage=Cada página?
addImage.upload=Adicionar imagem
addImage.submit=Adicionar imagem
#merge
merge.title=mesclar
merge.header=Mesclar vários PDFs (2+)
merge.submit=mesclar
#pdfOrganiser
pdfOrganiser.title=Organizador de página
pdfOrganiser.header=Organizador de páginas PDF
pdfOrganiser.submit=Reorganizar páginas
#multiTool
multiTool.title=Multiferramenta de PDF
multiTool.header=Multiferramenta de PDF
#pageRemover
pageRemover.title=Removedor de página
pageRemover.header=Removedor de página PDF
pageRemover.pagesToDelete=Páginas a serem excluídas (digite uma lista separada por vírgulas de números de página):
pageRemover.submit=Excluir páginas
#rotate
rotate.title=Girar PDF
rotate.header=Girar PDF
rotate.selectAngle=Selecione o ângulo de rotação (em múltiplos de 90 graus):
rotate.submit=Girar
#merge
split.title=PDF dividido
split.header=PDF dividido
split.desc.1=Os números que você selecionar são o número da página na qual você deseja fazer uma divisão
split.desc.2=Assim, selecionar 1,3,7-8 dividiria um documento de 10 páginas em 6 PDFS separados com:
split.desc.3=Documento nº 1: página 1
split.desc.4=Documento nº 2: páginas 2 e 3
split.desc.5=Documento nº 3: Página 4, 5 e 6
split.desc.6=Documento nº 4: página 7
split.desc.7=Documento nº 5: página 8
split.desc.8=Documento nº 6: páginas 9 e 10
split.splitPages=Digite as páginas para dividir:
split.submit=Dividir
#merge
imageToPDF.title=Imagem para PDF
imageToPDF.header=Imagem para PDF
imageToPDF.submit=Converter
imageToPDF.selectText.1=Esticar para caber
imageToPDF.selectText.2=Girar PDF automaticamente
imageToPDF.selectText.3=Lógica de vários arquivos (Ativado apenas se estiver trabalhando com várias imagens)
imageToPDF.selectText.4=Mesclar em um único PDF
imageToPDF.selectText.5=Converter em PDFs separados
#pdfToImage
pdfToImage.title=PDF para imagem
pdfToImage.header=PDF para imagem
pdfToImage.selectText=Formato de imagem
pdfToImage.singleOrMultiple=Tipo de resultado de imagem
pdfToImage.single=Imagem grande única
pdfToImage.multi=Imagens múltiplas
pdfToImage.colorType=tipo de cor
pdfToImage.color=Cor
pdfToImage.grey=Escala de cinza
pdfToImage.blackwhite=Preto e branco (pode perder dados!)
pdfToImage.submit=Converter
#addPassword
addPassword.title=Adicionar senha
addPassword.header=Adicionar senha (Criptografar)
addPassword.selectText.1=Selecione PDF para criptografar
addPassword.selectText.2=Senha
addPassword.selectText.3=Comprimento da chave de criptografia
addPassword.selectText.4=Valores mais altos são mais fortes, mas valores mais baixos têm melhor compatibilidade.
addPassword.selectText.5=Permissões para definir
addPassword.selectText.6=Impedir a montagem do documento
addPassword.selectText.7=Impedir a extração de conteúdo
addPassword.selectText.8=Impedir a extração para acessibilidade
addPassword.selectText.9=Impedir o preenchimento do formulário
addPassword.selectText.10=Impedir modificação
addPassword.selectText.11=Impedir a modificação da anotação
addPassword.selectText.12=Impedir a impressão
addPassword.selectText.13=Impedir a impressão de formatos diferentes
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=criptografar
#watermark
watermark.title=Adicione uma Marca d'água
watermark.header=Adicione uma Marca d'água
watermark.selectText.1=Selecione PDF para adicionar marca d'água a:
watermark.selectText.2=Texto da marca d'água:
watermark.selectText.3=Tamanho da fonte:
watermark.selectText.4=Rotação (0-360):
watermark.selectText.5=widthSpacer (espaço entre cada marca d'água horizontalmente):
watermark.selectText.6=heightSpacer (espaço entre cada marca d'água verticalmente):
watermark.selectText.7=Opacidade (0% - 100%):
watermark.submit=Adicione uma Marca d'água
#remove-watermark
remove-watermark.title=Remover marca d'água
remove-watermark.header=Remover marca d'água
remove-watermark.selectText.1=Selecione PDF para remover a marca d'água de:
remove-watermark.selectText.2=Texto da marca d'água:
remove-watermark.submit=Remover marca d'água
#Change permissions
permissions.title=Alterar permissões
permissions.header=Alterar permissões
permissions.warning=Aviso para que essas permissões sejam inalteráveis, é recomendável defini-las com uma senha por meio da página adicionar senha
permissions.selectText.1=Selecione o PDF para alterar as permissões
permissions.selectText.2=Permissões para definir
permissions.selectText.3=Impedir a montagem do documento
permissions.selectText.4=Impedir a extração de conteúdo
permissions.selectText.5=Impedir extração para acessibilidade
permissions.selectText.6=Impedir o preenchimento do formulário
permissions.selectText.7=Impedir modificações
permissions.selectText.8=Impedir a modificação da anotação
permissions.selectText.9=Impedir a impressão
permissions.selectText.10=Impedir a impressão de formatos diferentes
permissions.submit=Mudar
#remove password
removePassword.title=Remover senha
removePassword.header=Remover senha (Descriptografar)
removePassword.selectText.1=Selecione PDF para descriptografar
removePassword.selectText.2=Senha
removePassword.submit=Remover
changeMetadata.title=Alterar metadados
changeMetadata.header=Alterar metadados
changeMetadata.selectText.1=Edite as variáveis que deseja alterar
changeMetadata.selectText.2=Excluir todos os metadados
changeMetadata.selectText.3=Mostrar metadados personalizados:
changeMetadata.author=Autor:
changeMetadata.creationDate=Data de Criação (aaaa/MM/dd HH:mm:ss):
changeMetadata.creator=O Criador:
changeMetadata.keywords=Palavras-chave:
changeMetadata.modDate=Data de modificação (aaaa/MM/dd HH:mm:ss):
changeMetadata.producer=Produtor:
changeMetadata.subject=Assunto:
changeMetadata.title=Título:
changeMetadata.trapped=Encurralado:
changeMetadata.selectText.4=Outros metadados:
changeMetadata.selectText.5=Adicionar entrada de metadados personalizados
changeMetadata.submit=Mudar
xlsToPdf.title=Excel para PDF
xlsToPdf.header=Excel para PDF
xlsToPdf.selectText.1=Selecione planilha Excel XLS ou XLSX para converter
xlsToPdf.convert=converter
pdfToPDFA.title=PDF para PDF/A
pdfToPDFA.header=PDF para PDF/A
pdfToPDFA.credit=Este serviço usa OCRmyPDF para conversão de PDF/A
pdfToPDFA.submit=Converter
PDFToWord.title=PDF para Word
PDFToWord.header=PDF para Word
PDFToWord.selectText.1=Formato do arquivo de saída
PDFToWord.credit=Este serviço usa o LibreOffice para conversão de arquivos.
PDFToWord.submit=Converter
PDFToPresentation.title=PDF para apresentação
PDFToPresentation.header=PDF para apresentação
PDFToPresentation.selectText.1=Formato do arquivo de saída
PDFToPresentation.credit=Este serviço usa o LibreOffice para conversão de arquivos.
PDFToPresentation.submit=Converter
PDFToText.title=PDF para Texto/RTF
PDFToText.header=PDF para Texto/RTF
PDFToText.selectText.1=Formato do arquivo de saída
PDFToText.credit=Este serviço usa o LibreOffice para conversão de arquivos.
PDFToText.submit=Converter
PDFToHTML.title=PDF para HTML
PDFToHTML.header=PDF para HTML
PDFToHTML.credit=Este serviço usa o LibreOffice para conversão de arquivos.
PDFToHTML.submit=Converter
PDFToXML.title=PDF para XML
PDFToXML.header=PDF para XML
PDFToXML.credit=Este serviço usa o LibreOffice para conversão de arquivos.
PDFToXML.submit=Converter

View File

@@ -20,6 +20,7 @@ close=Închide
filesSelected=fișiere selectate
noFavourites=Niciun favorit adăugat
bored=Plictisit așteptând?
alphabet=Alfabet
#############
# HOME-PAGE #
#############
@@ -109,12 +110,31 @@ home.compare.desc=Compară și arată diferențele dintre 2 documente PDF.
home.certSign.title=Semnare cu certificat
home.certSign.desc=Semnează un PDF cu un certificat/cheie (PEM/P12)
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=Descarcă PDF
text=Text
font=Font
selectFillter=-- Selectează --
pageNum=Numărul paginii
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title = Semnare certificat
certSign.header = Semnează un fișier PDF cu certificatul tău (În curs de desfășurare)
certSign.selectPDF = Selectează un fișier PDF pentru semnare:
@@ -234,6 +254,7 @@ compress.submit=Comprimare
addImage.title=Adăugare imagine
addImage.header=Adăugare imagine în PDF
addImage.everyPage=Pe fiecare pagină?
addImage.upload=Adăugare imagine
addImage.submit=Adăugare imagine
#merge
@@ -316,6 +337,9 @@ addPassword.selectText.10=Preveniți modificarea
addPassword.selectText.11=Preveniți modificarea adnotărilor
addPassword.selectText.12=Preveniți tipărirea
addPassword.selectText.13=Preveniți tipărirea în formate diferite
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Criptare
#watermark

View File

@@ -20,6 +20,7 @@ close=Закрыть
filesSelected=файлов выбрано
noFavourites=Нет избранного
bored=Скучно ждать?
alphabet=\u0430\u043B\u0444\u0430\u0432\u0438\u0442
#############
# HOME-PAGE #
#############
@@ -125,12 +126,34 @@ home.removeBlanks.desc=Обнаруживает и удаляет пустые
home.compare.title=Сравнение
home.compare.desc=Сравнивает и показывает различия между двумя PDF-документами
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=Скачать PDF
text=Текст
font=Шрифт
selectFillter=-- Выбрать --
pageNum=номер страницы
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Подписание сертификата
certSign.header=Подпишите PDF своим сертификатом (работа в процессе)
certSign.selectPDF=Выберите файл PDF для подписи:
@@ -251,6 +274,7 @@ compress.submit=Сжать
addImage.title=Добавить изображение
addImage.header=Добавить изображение в PDF
addImage.everyPage=Каждая страница?
addImage.upload=Добавить изображение
addImage.submit=Добавить изображение
@@ -338,6 +362,9 @@ addPassword.selectText.10=Предотвратить модификацию
addPassword.selectText.11=Запретить модификацию аннотаций
addPassword.selectText.12=Запретить печать
addPassword.selectText.13=Запретить печать разных форматов
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Шифровать
#watermark

View File

@@ -20,6 +20,7 @@ close=Stäng
filesSelected=filer valda
noFavourites=Inga favoriter har lagts till
bored=Utråkad att vänta?
alphabet=Alfabet
#############
# HEMSIDA #
#############
@@ -125,12 +126,34 @@ home.removeBlanks.desc=Känner av och tar bort tomma sidor från ett dokument
home.compare.title=Jämför
home.compare.desc=Jämför och visar skillnaderna mellan 2 PDF-dokument
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=Ladda ner PDF
text=Text
font=Teckensnitt
selectFillter=-- Välj --
pageNum=Sidnummer
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=Certifikatsignering
certSign.header=Skriv under en PDF med ditt certifikat (Pågående arbete)
certSign.selectPDF=Välj en PDF-fil för signering:
@@ -251,6 +274,7 @@ compress.submit=Komprimera
addImage.title=Lägg till bild
addImage.header=Lägg till bild till PDF
addImage.everyPage=Varje sida?
addImage.upload=Lägg till bild
addImage.submit=Lägg till bild
@@ -338,6 +362,9 @@ addPassword.selectText.10=Förhindra modifiering
addPassword.selectText.11=Förhindra anteckningsändring
addPassword.selectText.12=Förhindra utskrift
addPassword.selectText.13=Förhindra utskrift av olika format
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Kryptera
#vattenstämpel

View File

@@ -20,6 +20,7 @@ close=关闭
filesSelected=\u9009\u62E9\u7684\u6587\u4EF6
noFavourites=\u6CA1\u6709\u6DFB\u52A0\u6536\u85CF\u5939
bored=\u65E0\u804A\u7B49\u5F85\uFF1F
alphabet=\u5B57\u6BCD\u8868
#############
# HOME-PAGE #
#############
@@ -125,12 +126,34 @@ home.removeBlanks.desc=\u68C0\u6D4B\u5E76\u5220\u9664\u6587\u6863\u4E2D\u7684\u7
home.compare.title=\u6BD4\u8F83
home.compare.desc=\u6BD4\u8F83\u5E76\u663E\u793A 2 \u4E2A PDF \u6587\u6863\u4E4B\u95F4\u7684\u5DEE\u5F02
home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
home.scalePages.title=Adjust page size/scale
home.scalePages.desc=Change the size/scale of page and/or its contents.
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
downloadPdf=\u4E0B\u8F7DPDF
text=\u6587\u672C
font=\u5B57\u4F53
selectFillter=-- 选择--
pageNum=页码
pageLayout.title=Multi Page Layout
pageLayout.header=Multi Page Layout
pageLayout.pagesPerSheet=Pages per sheet:
pageLayout.submit=Submit
scalePages.title=Adjust page-scale
scalePages.header=Adjust page-scale
scalePages.pageSize=Size of a page of the document.
scalePages.scaleFactor=Zoom level (crop) of a page.
scalePages.submit=Submit
certSign.title=证书签名
certSign.header=使用您的证书签署 PDF进行中
certSign.selectPDF=选择要签名的 PDF 文件:
@@ -250,6 +273,7 @@ compress.submit=压缩
addImage.title=添加图像
addImage.header=添加图片到PDF (Work in progress)
addImage.everyPage=每一页?
addImage.upload=添加图片
addImage.submit=添加图片
@@ -336,7 +360,10 @@ addPassword.selectText.9=防止填写表格
addPassword.selectText.10=防止修改
addPassword.selectText.11=防止修改注释
addPassword.selectText.12=防止打印
addPassword.selectText.13=防止打印不同的格
addPassword.selectText.13=防止打印不同的格<EFBFBD>
addPassword.selectText.14=Owner Password
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Restricts the opening of the document itself<6C>
addPassword.submit=加密
#watermark

View File

@@ -0,0 +1,94 @@
#errorContainer {
margin: 20px; /* adjust this value as needed */
}
#helpModalDialog {
width: 90%;
max-width: 800px;
}
#helpModal h1 {
text-align: center;
margin-top: 10%;
}
#helpModal p {
text-align: center;
margin-top: 2em;
}
#helpModal .button:hover {
background-color: #005b7f;
}
#helpModal .features-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
gap: 25px 30px;
}
#helpModal .feature-card {
border: 1px solid rgba(0, 0, 0, .125);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
}
#helpModal .feature-card .card-text {
flex: 1;
}
#support-section {
background-color: #f9f9f9;
padding: 4rem;
margin-top: 1rem;
text-align: center;
}
#support-section h1 {
margin-top: 0;
}
#support-section p {
margin-top: 0;
}
#button-group {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
#github-button, #discord-button {
display: inline-block;
padding: 1rem 2rem;
margin: 1rem;
background-color: #008CBA;
color: #fff;
font-size: 1.2rem;
text-align: center;
text-decoration: none;
border-radius: 3rem;
transition: all 0.3s ease-in-out;
}
#github-button:hover, #discord-button:hover, #home-button:hover {
background-color: #005b7f;
}
#home-button {
display: block;
width: 200px;
height: 50px;
margin: 2em auto;
background-color: #008CBA;
color: white;
text-align: center;
line-height: 50px;
text-decoration: none;
font-weight: bold;
border-radius: 25px;
transition: all 0.3s ease-in-out;
}

View File

@@ -0,0 +1,10 @@
.custom-file-label {
padding-right: 90px;
}
.selected-files {
margin-top: 10px;
max-height: 150px;
overflow-y: auto;
white-space: pre-wrap;
}

View File

@@ -0,0 +1,49 @@
#game-container {
position: relative;
width: 100vh;
height: 0;
padding-bottom: 75%; /* 4:3 aspect ratio */
background-color: transparent;
margin: auto;
overflow: hidden;
border: 2px solid black; /* Add border */
}
.pdf, .player, .projectile {
position: absolute;
}
.pdf {
width: 50px;
height: 50px;
}
.player {
width: 50px;
height: 50px;
}
.projectile {
background-color: black !important;
width: 5px;
height: 10px;
}
#score, #level, #lives, #high-score {
color: black;
font-family: sans-serif;
position: absolute;
font-size: calc(14px + 0.25vw); /* Reduced font size */
}
#score {
top: 10px;
left: 10px;
}
#lives {
top: 10px;
left: calc(7vw); /* Adjusted position */
}
#high-score {
top: 10px;
left: calc(14vw); /* Adjusted position */
}
#level {
top: 10px;
right: 10px;
}

View File

@@ -0,0 +1,70 @@
.features-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
gap: 25px 30px;
}
.feature-card {
border: 2px solid rgba(0, 0, 0, .25);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
background: rgba(13, 110, 253, 0.05);
transition: transform 0.3s, border 0.3s;
}
.feature-card a {
text-decoration: none;
color: inherit;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.feature-card .card-text {
flex: 1;
}
.feature-card:hover {
border: 1px solid rgba(0, 0, 0, .5);
cursor: pointer;
transform: scale(1.1);
}
.feature-card:hover .card-title {
text-decoration: underline;
}
.card-title.text-primary {
color: #000; /* Replace with your desired shade of blue */
}
.home-card-icon {
width: 30px;
height: 30px;
transform: translateY(-5px);
}
.home-card-icon-colour {
filter: invert(0.2) sepia(2) saturate(50) hue-rotate(190deg);
}
.favorite-icon {
display: none;
position: absolute;
top: 10px;
right: 10px;
}
/* Only show the favorite icons when the parent card is being hovered over */
.feature-card:hover .favorite-icon {
display: block;
}
.favorite-icon img {
filter: brightness(0);
}
.jumbotron {
padding: 3rem 3rem; /* Reduce vertical padding */
}

View File

@@ -0,0 +1,25 @@
.list-group-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.filename {
flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.arrows {
flex-shrink: 0;
display: flex;
justify-content: flex-end;
}
.move-up span,
.move-down span {
font-weight: bold;
font-size: 1.2em;
}

View File

@@ -0,0 +1,42 @@
.main-icon {
width: 36px;
height: 36px;
vertical-align: middle;
transform: translateY(-2px);
}
.icon {
width: 16px;
height: 16px;
vertical-align: middle;
transform: translateY(-2px);
}
.icon+.icon {
margin-left: -4px;
}
.icon-text {
margin-left: 4px;
}
.nav-item-separator {
position: relative;
margin: 0 4px; /* Adjust the margin as needed */
}
.nav-item-separator::before {
content: '';
position: absolute;
left: 0;
top: 10%; /* Adjust the top and bottom margins as needed */
bottom: 10%;
width: 1px;
background-color: #ccc; /* Adjust the color as needed */
}
.navbar-icon {
width: 20px;
height: 20px;
transform: translateY(-2px);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-es-pv" viewBox="0 0 640 480">
<path fill="#D52B1E" d="m0 0h640v480h-640z" />
<path fill="#009B48" d="m0 0h53.1l133.4 100.1c73.4 55 133.4 100 133.5 100 0.1 0 60.1-45 266.9-200.1h53.1v39.9l-133.4 100c-73.4 55-133.4 100.1-133.4 100.1 0 0 60 45.1 266.8 200.2v39.8h-53.1l-133.4-100c-73.4-55.1-133.4-100.1-133.5-100.1-0.1 0-60.1 45-266.9 200.1h-53.1v-39.8l133.4-100.1c73.4-55 133.4-100.1 133.4-100.1 0 0-60-45.1-266.8-200.1v-20z" />
<path fill="#FFF" d="m288.1 0h63.8v208.1h288.1v63.8h-288.1v208.1h-63.8v-208.1h-288.1v-63.8h288.1v-104z" />
</svg>

After

Width:  |  Height:  |  Size: 602 B

View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-jp" viewBox="0 0 640 480">
<defs>
<clipPath id="a">
<path fill-opacity=".7" d="M-88 32h640v480H-88z"/>
</clipPath>
</defs>
<g fill-rule="evenodd" stroke-width="1pt" clip-path="url(#a)" transform="translate(88 -32)">
<path fill="#fff" d="M-128 32h720v480h-720z"/>
<circle cx="523.1" cy="344.1" r="194.9" fill="#bc002d" transform="translate(-168.4 8.6) scale(.76554)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 465 B

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1060" height="742" version="1.1" viewBox="-2100 -1470 4200 2940" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="G">
<clipPath id="gcut">
<path d="m-31.5 0v-70h63v70zm31.5-47v12h31.5v-12z"/>
</clipPath>
<use width="100%" height="100%" clip-path="url(#gcut)" xlink:href="#O"/>
<path d="M5-35H31.5V-25H5z"/>
<path d="m21.5-35h10v35h-10z"/>
</g>
<g id="R">
<use width="100%" height="100%" xlink:href="#P"/>
<path d="m28 0c0-10 0-32-15-32h-19c22 0 22 22 22 32"/>
</g>
<g id="star" fill="#fff">
<g id="c">
<path id="t" transform="rotate(18,0,-1)" d="m0-1v1h0.5"/>
<use transform="scale(-1,1)" width="100%" height="100%" xlink:href="#t"/>
</g>
<use transform="rotate(72)" width="100%" height="100%" xlink:href="#c"/>
<use transform="rotate(-72)" width="100%" height="100%" xlink:href="#c"/>
<use transform="rotate(144)" width="100%" height="100%" xlink:href="#c"/>
<use transform="rotate(216)" width="100%" height="100%" xlink:href="#c"/>
</g>
<g id="star1">
<use transform="scale(31.5)" width="100%" height="100%" xlink:href="#star"/>
</g>
<g id="star2">
<use transform="scale(26.25)" width="100%" height="100%" xlink:href="#star"/>
</g>
<g id="star3">
<use transform="scale(21)" width="100%" height="100%" xlink:href="#star"/>
</g>
<g id="star4">
<use transform="scale(15)" width="100%" height="100%" xlink:href="#star"/>
</g>
<g id="star5">
<use transform="scale(10.5)" width="100%" height="100%" xlink:href="#star"/>
</g>
<path id="D" d="m-31.5 0h33a30 30 0 0 0 30-30v-10a30 30 0 0 0-30-30h-33zm13-13h19a19 19 0 0 0 19-19v-6a19 19 0 0 0-19-19h-19z" fill-rule="evenodd"/>
<path id="E" transform="translate(-31.5)" d="m0 0h63v-13h-51v-18h40v-12h-40v-14h48v-13h-60z"/>
<path id="e" d="m-26.25 0h52.5v-12h-40.5v-16h33v-12h-33v-11h39.25v-12h-51.25z"/>
<path id="M" d="m-31.5 0h12v-48l14 48h11l14-48v48h12v-70h-17.5l-14 48-14-48h-17.5z"/>
<path id="O" d="m0 0a31.5 35 0 0 0 0-70 31.5 35 0 0 0 0 70m0-13a18.5 22 0 0 0 0-44 18.5 22 0 0 0 0 44" fill-rule="evenodd"/>
<path id="P" d="m-31.5 0h13v-26h28a22 22 0 0 0 0-44h-40zm13-39h27a9 9 0 0 0 0-18h-27z" fill-rule="evenodd"/>
<path id="S" d="m-15.75-22c0 7 6.75 10.5 16.75 10.5s14.74-3.25 14.75-7.75c0-14.25-46.75-5.25-46.5-30.25 0.25-21.5 24.75-20.5 33.75-20.5s26 4 25.75 21.25h-15.25c0-7.5-7-10.25-15-10.25-7.75 0-13.25 1.25-13.25 8.5-0.25 11.75 46.25 4 46.25 28.75 0 18.25-18 21.75-31.5 21.75-11.5 0-31.55-4.5-31.5-22z"/>
</defs>
<clipPath id="band">
<circle r="735"/>
</clipPath>
<path d="m-2100-1470h4200v2940h-4200z" fill="#009b3a"/>
<path d="M -1743,0 0,1113 1743,0 0,-1113 Z" fill="#fedf00"/>
<circle r="735" fill="#002776"/>
<path d="m-2205 1470a1785 1785 0 0 1 3570 0h-105a1680 1680 0 1 0-3360 0z" clip-path="url(#band)" fill="#fff"/>
<g transform="translate(-420,1470)" fill="#009b3a">
<use transform="rotate(-7)" y="-1697.5" width="100%" height="100%" xlink:href="#O"/>
<use transform="rotate(-4)" y="-1697.5" width="100%" height="100%" xlink:href="#R"/>
<use transform="rotate(-1)" y="-1697.5" width="100%" height="100%" xlink:href="#D"/>
<use transform="rotate(2)" y="-1697.5" width="100%" height="100%" xlink:href="#E"/>
<use transform="rotate(5)" y="-1697.5" width="100%" height="100%" xlink:href="#M"/>
<use transform="rotate(9.75)" y="-1697.5" width="100%" height="100%" xlink:href="#e"/>
<use transform="rotate(14.5)" y="-1697.5" width="100%" height="100%" xlink:href="#P"/>
<use transform="rotate(17.5)" y="-1697.5" width="100%" height="100%" xlink:href="#R"/>
<use transform="rotate(20.5)" y="-1697.5" width="100%" height="100%" xlink:href="#O"/>
<use transform="rotate(23.5)" y="-1697.5" width="100%" height="100%" xlink:href="#G"/>
<use transform="rotate(26.5)" y="-1697.5" width="100%" height="100%" xlink:href="#R"/>
<use transform="rotate(29.5)" y="-1697.5" width="100%" height="100%" xlink:href="#E"/>
<use transform="rotate(32.5)" y="-1697.5" width="100%" height="100%" xlink:href="#S"/>
<use transform="rotate(35.5)" y="-1697.5" width="100%" height="100%" xlink:href="#S"/>
<use transform="rotate(38.5)" y="-1697.5" width="100%" height="100%" xlink:href="#O"/>
</g>
<use id="αCMi" x="-600" y="-132" width="100%" height="100%" xlink:href="#star1"/>
<use id="αCMa" x="-535" y="177" width="100%" height="100%" xlink:href="#star1"/>
<use id="βCMa" x="-625" y="243" width="100%" height="100%" xlink:href="#star2"/>
<use id="γCMa" x="-463" y="132" width="100%" height="100%" xlink:href="#star4"/>
<use id="δCMa" x="-382" y="250" width="100%" height="100%" xlink:href="#star2"/>
<use id="εCMa" x="-404" y="323" width="100%" height="100%" xlink:href="#star3"/>
<use id="αVir" x="228" y="-228" width="100%" height="100%" xlink:href="#star1"/>
<use id="αSco" x="515" y="258" width="100%" height="100%" xlink:href="#star1"/>
<use id="βSco" x="617" y="265" width="100%" height="100%" xlink:href="#star3"/>
<use id="εSco" x="545" y="323" width="100%" height="100%" xlink:href="#star2"/>
<use id="θSco" x="368" y="477" width="100%" height="100%" xlink:href="#star2"/>
<use id="ιSco" x="367" y="551" width="100%" height="100%" xlink:href="#star3"/>
<use id="κSco" x="441" y="419" width="100%" height="100%" xlink:href="#star3"/>
<use id="λSco" x="500" y="382" width="100%" height="100%" xlink:href="#star2"/>
<use id="μSco" x="365" y="405" width="100%" height="100%" xlink:href="#star3"/>
<use id="αHya" x="-280" y="30" width="100%" height="100%" xlink:href="#star2"/>
<use id="γHya" x="200" y="-37" width="100%" height="100%" xlink:href="#star3"/>
<use id="αCru" y="330" width="100%" height="100%" xlink:href="#star1"/>
<use id="βCru" x="85" y="184" width="100%" height="100%" xlink:href="#star2"/>
<use id="γCru" y="118" width="100%" height="100%" xlink:href="#star2"/>
<use id="δCru" x="-74" y="184" width="100%" height="100%" xlink:href="#star3"/>
<use id="εCru" x="-37" y="235" width="100%" height="100%" xlink:href="#star4"/>
<use id="αTrA" x="220" y="495" width="100%" height="100%" xlink:href="#star2"/>
<use id="βTrA" x="283" y="430" width="100%" height="100%" xlink:href="#star3"/>
<use id="γTrA" x="162" y="412" width="100%" height="100%" xlink:href="#star3"/>
<use id="αCar" x="-295" y="390" width="100%" height="100%" xlink:href="#star1"/>
<use id="σOct" y="575" width="100%" height="100%" xlink:href="#star5"/>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-grid" viewBox="0 0 16 16">
<path d="M1 2.5A1.5 1.5 0 0 1 2.5 1h3A1.5 1.5 0 0 1 7 2.5v3A1.5 1.5 0 0 1 5.5 7h-3A1.5 1.5 0 0 1 1 5.5v-3zM2.5 2a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 1h3A1.5 1.5 0 0 1 15 2.5v3A1.5 1.5 0 0 1 13.5 7h-3A1.5 1.5 0 0 1 9 5.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zM1 10.5A1.5 1.5 0 0 1 2.5 9h3A1.5 1.5 0 0 1 7 10.5v3A1.5 1.5 0 0 1 5.5 15h-3A1.5 1.5 0 0 1 1 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 9h3a1.5 1.5 0 0 1 1.5 1.5v3a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3z"/>
</svg>

After

Width:  |  Height:  |  Size: 880 B

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