Compare commits

..

155 Commits

Author SHA1 Message Date
github-actions[bot]
d575ba8f9a 💾 Update Version (#1461)
💾 Sync Versions
> Made via sync_files.yml

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

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

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

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

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

* Add process method to merge odd and even PDF pages

* Add test cases for Odd-Even merge method

* Add Odd-Even Merge mode in PDF Organizer webpage

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

* Add ODD_EVEN_MERGE documentation to RearrangePagesRequest

* Add english translation for pdfOrganiser.mode.10

---------

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

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

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

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

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

* change path
2024-06-12 20:33:25 +01:00
Abdulwahhab A Alzahrani
76660eb791 Update messages_ar_AR.properties (#1430)
translate to Arabic
2024-06-09 21:20:35 +01:00
github-actions[bot]
e0ce3c90de 💾 Update Version (#1429)
💾 Sync Versions
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-09 17:45:13 +01:00
Anthony Stirling
aaf94fa981 Update build.gradle 2024-06-09 17:44:31 +01:00
dependabot[bot]
d1aa56266e Bump gradle from 7.6-jdk17 to 8.0-jdk17 (#1371)
* Bump gradle from 7.6-jdk17 to 8.0-jdk17

Bumps gradle from 7.6-jdk17 to 8.0-jdk17.

---
updated-dependencies:
- dependency-name: gradle
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Dockerfile-fat

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-09 16:00:04 +01:00
github-actions[bot]
790d4f053d Update 3rd Party Licenses (#1428)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-06-09 15:56:15 +01:00
dependabot[bot]
e5b25ac8a5 Bump commons-io:commons-io from 2.15.1 to 2.16.1 (#1055)
Bumps commons-io:commons-io from 2.15.1 to 2.16.1.

---
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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-09 15:54:50 +01:00
Anthony Stirling
b365155e62 Update githubVersion.js 2024-06-09 15:30:20 +01:00
github-actions[bot]
f4f80a54a8 📝 Update README: Translation Progress Table (#1427)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-09 14:20:42 +01:00
github-actions[bot]
681a8d3443 📝 Update README: Translation Progress Table (#1426)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-09 14:05:16 +01:00
Ludy
7543f49ba4 Add: Option to remove the digital signature when merging (#1424) 2024-06-09 13:58:05 +01:00
albanobattistella
2e11b632dd Update messages_it_IT.properties (#1423) 2024-06-09 13:57:13 +01:00
Anthony Stirling
63bdc0d59e Pipeline fixes for json lists + delete func (#1425)
* init

* revert

* pipelines fixes for lists

* pipeline fixes to allow json lists

* formatting

* pipeline changes

* langs

---------

Co-authored-by: a <a>
2024-06-09 13:56:55 +01:00
Anthony Stirling
56fdf1f3a1 Feature request template (#1422)
* Create 2-feature.yml

* Update 2-feature.yml

* Update 2-feature.yml
2024-06-09 11:06:17 +01:00
Ludy
a6069c0f9e Add template for bug issues (#1419) 2024-06-09 10:45:36 +01:00
Ludy
327a44d487 Bump PDF.js from 4.3.118 to 4.3.136 (#1420)
Changelog: https://github.com/mozilla/pdf.js/releases/tag/v4.3.136
2024-06-09 10:45:25 +01:00
Ludy
7a15930453 add password validator (#1418) 2024-06-08 22:36:23 +01:00
github-actions[bot]
517e54517c 📝 Update README: Translation Progress Table (#1416)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-08 16:07:54 +01:00
Anthony Stirling
ef59ea6fe4 Images and login context (#1417)
* init

* revert
2024-06-08 16:07:23 +01:00
imgbot[bot]
10472a6467 [ImgBot] Optimize images (#1412)
*Total -- 412.00kb -> 334.04kb (18.92%)

/images/settings.png -- 12.04kb -> 5.53kb (54.07%)
/images/stirling-home-light.png -- 118.54kb -> 81.18kb (31.51%)
/images/login-light.png -- 30.08kb -> 24.98kb (16.94%)
/images/login-dark.png -- 29.44kb -> 25.32kb (13.98%)
/images/stirling-home.jpg -- 166.42kb -> 144.85kb (12.96%)
/docs/stirling-pdf.png -- 53.00kb -> 49.69kb (6.24%)
/src/main/resources/static/pdfjs/images/loading-icon.gif -- 2.49kb -> 2.48kb (0.35%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2024-06-08 15:55:41 +01:00
Ludy
9a9429c15c Bugfix: fixes API query, replaces password comparisons, fixes duplicate ids (#1415)
fixes API query, replaces password comparisons, fixes duplicate ids
2024-06-08 12:37:06 +01:00
github-actions[bot]
b17912d607 📝 Update README: Translation Progress Table (#1414)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-07 22:59:41 +01:00
albanobattistella
ff315d9d96 Update messages_it_IT.properties (#1413) 2024-06-07 22:58:51 +01:00
github-actions[bot]
67f72ad17b 📝 Update README: Translation Progress Table (#1410)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-06-07 22:27:58 +01:00
Ludy
8f55c38391 add: redesign addUsers.html (#1407)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-06-07 22:27:16 +01:00
Anthony Stirling
8245d77c84 Merge pull request #1406 from SorCelien/main
New fr_FR ignore
2024-06-07 22:24:01 +01:00
Anthony Stirling
f5628f16d9 Merge branch 'main' into main 2024-06-07 22:22:32 +01:00
Anthony Stirling
47907daea0 Merge pull request #1405 from SorCelien/patch-1
fr messages: more translations
2024-06-07 22:21:55 +01:00
Anthony Stirling
664253532e Merge pull request #1404 from Ludy87/bypass_github
Add: Bypass for too many requests to the github api
2024-06-07 22:20:44 +01:00
Célien
6108b38098 Merge pull request #1 from SorCelien/patch-1
fr messages: more translations
2024-06-07 18:06:37 +02:00
Célien
a634c63176 New fr_FR ignore 2024-06-07 17:45:21 +02:00
Célien
109ed6a719 Nex fr_FR ignore 2024-06-07 17:40:33 +02:00
Célien
ac9312bd7e fr messages: more translations
mainly oauth translations
2024-06-07 17:35:36 +02:00
Ludy87
a743493cd3 Update navbar.html 2024-06-07 17:24:42 +02:00
Ludy87
c35355f01a Update githubVersion.js 2024-06-07 17:07:14 +02:00
Ludy87
ed910da288 Add: Bypass for too many requests to the github api 2024-06-07 16:54:47 +02:00
Anthony Stirling
fc0878704d Merge pull request #1385 from jimdouk/main
Enhance Test Coverage for SPDF/Utils Classes
2024-06-07 09:38:56 +01:00
Anthony Stirling
d5c71c8425 Merge pull request #1399 from Stirling-Tools/sync_version
💾 Update Version
2024-06-07 09:38:24 +01:00
GitHub Action action@github.com
afbe8f7abe 💾 Sync Versions
> Made via sync_files.yml
2024-06-07 08:37:00 +00:00
Anthony Stirling
3a97ff0e5e Update build.gradle 2024-06-07 09:36:46 +01:00
Anthony Stirling
4f5b19edfb Merge pull request #1397 from Stirling-Tools/pixeebot/drip-2024-06-07-sonar-java/avoid-implicit-public-constructor-s1118
(Sonar) Fixed finding: "Utility classes should not have public constructors"
2024-06-07 09:09:10 +01:00
pixeebot[bot]
88338b4dbc (Sonar) Fixed finding: "Utility classes should not have public constructors" 2024-06-07 07:52:26 +00:00
jimdouk
fc249661e2 Merge branch 'main' of https://github.com/jimdouk/Stirling-PDF 2024-06-07 10:38:21 +03:00
jimdouk
805848e627 Fix one test in Class ProcessExecutorTest 2024-06-07 10:38:05 +03:00
Dimitris Doukas
fdae1c9756 Merge branch 'main' into main 2024-06-07 09:21:06 +03:00
Anthony Stirling
32b3cfca41 Merge pull request #1396 from Stirling-Tools/pixeebot/drip-2024-06-07-sonar-java/add-missing-override-s1161
(Sonar) Fixed finding: "`@Override` should be used on overriding and implementing methods"
2024-06-07 06:27:02 +01:00
pixeebot[bot]
9147d364bc (Sonar) Fixed finding: "@Override should be used on overriding and implementing methods" 2024-06-07 04:38:10 +00:00
Anthony Stirling
6606850e4a fix version number 2024-06-06 22:38:22 +01:00
Anthony Stirling
7b08d98232 Merge pull request #1394 from Stirling-Tools/disableConfigUpdater
Disable config updater
2024-06-06 22:05:53 +01:00
Anthony Stirling
03150c6462 format 2024-06-06 21:59:13 +01:00
a
a3bf7baf35 Merge branch 'disableConfigUpdater' of git@github.com:Stirling-Tools/Stirling-PDF.git into disableConfigUpdater 2024-06-06 21:57:30 +01:00
Anthony Stirling
6c09bcf23c resolve #1386 2024-06-06 21:57:18 +01:00
Anthony Stirling
e11fa01d10 Merge pull request #1393 from Stirling-Tools/disableConfigUpdater
resolve admin config with custom path
2024-06-06 21:43:15 +01:00
Anthony Stirling
d60107f48b Merge branch 'main' into disableConfigUpdater 2024-06-06 21:36:04 +01:00
Anthony Stirling
0b449af9ba resolve path 2024-06-06 21:34:56 +01:00
Anthony Stirling
4c9c0207ba fancy button 2024-06-06 21:27:58 +01:00
Anthony Stirling
d36a59442f th action 2024-06-06 21:24:41 +01:00
Anthony Stirling
fd4c75279f init 2024-06-06 21:23:33 +01:00
Anthony Stirling
fd5f5025ce Merge pull request #1391 from Stirling-Tools/sync_version
💾 Update Version
2024-06-06 20:34:52 +01:00
GitHub Action action@github.com
319ecbcbc1 💾 Sync Versions
> Made via sync_files.yml
2024-06-06 19:23:20 +00:00
Anthony Stirling
04b0bcde61 Merge pull request #1388 from Stirling-Tools/disableConfigUpdater
remove settings files update for now
2024-06-06 20:23:04 +01:00
Anthony Stirling
6499b759d9 Merge pull request #1390 from Ludy87/replace_hardcoded
Enhance OAuth2 Client Registration with Dynamic Provider Details
2024-06-06 20:22:40 +01:00
Anthony Stirling
2081c4872d Merge pull request #1389 from Ludy87/fix_langues_cz_de_nb
Minor corrections in the languages
2024-06-06 20:21:05 +01:00
Ludy87
37c75971f2 Update ApplicationProperties.java 2024-06-06 21:14:34 +02:00
Ludy87
7d9edfca6d Enhance OAuth2 Client Registration with Dynamic Provider Details 2024-06-06 21:03:06 +02:00
Anthony Stirling
a40696f16e remove settings files update for now 2024-06-06 19:49:53 +01:00
Ludy87
515b5b1492 Minor corrections in the languages 2024-06-06 20:42:50 +02:00
jimdouk
5277cf2b59 Add junit tests for utils classes 2024-06-06 12:54:12 +03:00
Anthony Stirling
e824a3e7bd Update build.gradle 2024-06-05 23:18:52 +01:00
Anthony Stirling
9fd508fcc7 Update README.md 2024-06-05 23:17:38 +01:00
Anthony Stirling
a0227a4bdd Merge pull request #1382 from Stirling-Tools/tweaks
tweaks and fix for #1381
2024-06-05 22:35:22 +01:00
Anthony Stirling
87be41117f tweaks and fix for #1381 2024-06-05 21:16:22 +01:00
Anthony Stirling
3e9123fcd5 Merge pull request #1376 from arsvendg/main
Small adjustmens to language file
2024-06-05 18:28:48 +01:00
arsvendg
7e7c6a3832 Small adjustmens to language file 2024-06-05 13:21:17 +02:00
Anthony Stirling
cce31ee0f6 Merge pull request #1373 from arsvendg/main
Norwegian translation
2024-06-05 08:40:19 +01:00
arsvendg
746f341d6a Merge branch 'Stirling-Tools:main' into main 2024-06-05 09:07:11 +02:00
Anthony Stirling
f35bf120e9 Update flatten.html 2024-06-04 20:17:27 +01:00
arsvendg
1fd4ce339f Update languages.html 2024-06-04 00:05:34 +02:00
arsvendg
af736ca33a Add files via upload 2024-06-04 00:03:56 +02:00
arsvendg
0878dd10b8 Add files via upload 2024-06-04 00:03:23 +02:00
Anthony Stirling
948ddb06bc Merge pull request #1362 from Stirling-Tools/sonar
Sonar
2024-06-02 12:12:41 +01:00
Anthony Stirling
efc07522ab minor 2024-06-02 12:04:29 +01:00
Anthony Stirling
31938b662c format 2024-06-02 12:02:01 +01:00
Anthony Stirling
eb526a5d0c logging and try catch 2024-06-02 11:59:43 +01:00
Anthony Stirling
c4a620e3f5 init sonar 2024-06-02 11:42:30 +01:00
Anthony Stirling
17bf6237a2 Update push-docker.yml 2024-06-02 10:52:08 +01:00
Anthony Stirling
086daf8351 Merge pull request #1361 from Stirling-Tools/sync_version
💾 Update Version
2024-06-02 10:32:41 +01:00
GitHub Action action@github.com
2741094a8a 💾 Sync Versions
> Made via sync_files.yml
2024-06-02 09:28:30 +00:00
Anthony Stirling
b4dc766f7a Update build.gradle 2024-06-02 10:28:16 +01:00
Anthony Stirling
75e2cfb234 Merge pull request #1359 from albanobattistella/patch-29
Update messages_it_IT.properties
2024-06-01 22:32:34 +01:00
Anthony Stirling
c5f7000e72 Merge pull request #1360 from Ludy87/remove_digi_sign
new workaround for remove digital signature
2024-06-01 22:31:05 +01:00
Ludy87
ca0432e0b4 notification 2024-06-01 21:33:21 +02:00
Ludy87
5799e61385 new workaround for remove digital signature 2024-06-01 21:30:05 +02:00
albanobattistella
f2784c85d6 Update messages_it_IT.properties 2024-06-01 21:07:02 +02:00
Anthony Stirling
01a3fa8cfe Update push-docker.yml 2024-06-01 14:12:57 +01:00
Anthony Stirling
41138cb2be Merge pull request #1356 from Stirling-Tools/fatDockerAutomation
automate fat docker
2024-06-01 14:03:20 +01:00
Anthony Stirling
995de6abc3 automate fat docker 2024-06-01 13:55:28 +01:00
Anthony Stirling
36deb32f07 Merge pull request #1355 from Stirling-Tools/fatDocker
fat docker
2024-06-01 13:06:51 +01:00
Anthony Stirling
6a38c55867 remove headless due to com.sun.imageio.plugins.jpeg.JPEGImageWriter 2024-06-01 12:57:11 +01:00
Anthony Stirling
96e390c98d Merge branch 'main' into fatDocker 2024-06-01 12:41:51 +01:00
Anthony Stirling
52978ec9ad fat docker 2024-06-01 12:38:10 +01:00
Anthony Stirling
fcd4af2d09 Merge pull request #1354 from foivospro/main
Fix Error When Submitting Crop Tool Without Making a Selection
2024-06-01 12:02:18 +01:00
foiv
963c1f4874 fix the crop problem 2024-06-01 13:58:56 +03:00
Anthony Stirling
aa42806a9e Merge pull request #1352 from Ludy87/fix_admin_exe_windows
Fix: Initialization Issue and Enhance Configuration Management for Co…
2024-06-01 09:41:54 +01:00
Ludy87
19c564a6f7 Fix: Initialization Issue and Enhance Configuration Management for ConfigInitializer #1324 2024-05-31 23:51:42 +02:00
Anthony Stirling
6afbd8bd24 Update build.gradle 2024-05-31 21:04:42 +01:00
Anthony Stirling
76bfc09a44 Merge pull request #1344 from andrewdolphin/main
Update view-pdf.html
2024-05-31 20:55:22 +01:00
Anthony Stirling
6df412c576 Merge pull request #1347 from Stirling-Tools/sync_readme
📝 Update README: Translation Progress Table
2024-05-31 20:55:09 +01:00
Anthony Stirling
37bb890cb9 Merge branch 'main' into sync_readme 2024-05-31 20:54:55 +01:00
Anthony Stirling
9bd15d7ef3 Update README.md 2024-05-31 20:53:05 +01:00
Anthony Stirling
b0671943f7 Merge pull request #1345 from onyxfin/main
Croatian language Translation.
2024-05-31 20:50:30 +01:00
GitHub Action action@github.com
7cbad4df4f 📝 Sync README
> Made via sync_files.yml
2024-05-31 19:50:13 +00:00
Anthony Stirling
e27651826e Merge pull request #1346 from Ludy87/remove_cert_sign
add remove digital signature
2024-05-31 20:49:57 +01:00
onyxfin
5b0de9eac1 Update languages.html 2024-05-31 15:45:47 +02:00
onyxfin
b646d8c481 Add files via upload 2024-05-31 15:24:01 +02:00
andrewdolphin
cd2f628168 Update view-pdf.html
Remove bootstrap.css which regresses a previous issue that caused imported images to incorrectly resize.

Reintroduce "Import image" option.
2024-05-31 12:16:57 +01:00
Ludy87
aef0d32b5b add remove digital signature 2024-05-31 11:31:07 +02:00
onyxfin
e761ad8e51 Merge pull request #1 from onyxfin/onyxfin-patch-1
Add files via upload
2024-05-30 22:11:09 +02:00
onyxfin
059296d444 Add files via upload 2024-05-30 22:01:29 +02:00
Anthony Stirling
9c1de1cb10 Merge pull request #1336 from Stirling-Tools/sync_readme
📝 Update README: Translation Progress Table
2024-05-30 20:55:34 +01:00
Anthony Stirling
ebba39ce10 Merge pull request #1334 from Ludy87/fix_docker_sso
add properties Docker
2024-05-30 20:54:28 +01:00
Anthony Stirling
361b4c2db4 Merge pull request #1333 from Ludy87/fix_viewer_pdf
Fix: Can't select the Draw tool in View #1328
2024-05-30 20:54:15 +01:00
Anthony Stirling
d221654121 Merge pull request #1331 from pcanham/hotfix/typo-fix-for-google
fix: type correction around google OAUTH2 provider
2024-05-30 20:54:08 +01:00
GitHub Action action@github.com
7ac41d7863 📝 Sync README
> Made via sync_files.yml
2024-05-30 19:54:03 +00:00
Anthony Stirling
f1476d197f Merge pull request #1326 from NicolasFR/feat/utf8-mdToPdf
feat: Force UTF-8 encoding of input characters
2024-05-30 20:53:58 +01:00
Anthony Stirling
4a53195c25 Merge pull request #1322 from albanobattistella/patch-28
Update messages_it_IT.properties
2024-05-30 20:53:50 +01:00
Anthony Stirling
e2bed6f6af Merge pull request #1321 from nimdassdev/main
Update messages_bg_BG.properties
2024-05-30 20:53:45 +01:00
Anthony Stirling
5d6e23d4b7 Merge pull request #1282 from kkdlau/bugfix/1214-grab-zero-byte-pdf
#1214 Only take pdf that are good for processing
2024-05-30 20:53:21 +01:00
Ludy87
dfb8ba857f add properties Docker 2024-05-30 11:52:13 +02:00
Ludy87
1572404e6f Fix: Can't select the Draw tool in View #1328 2024-05-30 11:42:49 +02:00
Paul Canham
76dc90d587 fi: type correction around google OAUTH2 provider 2024-05-30 09:42:23 +01:00
Anthony Stirling
316b4e42af Update README.md 2024-05-29 23:36:14 +01:00
Nicolas
f61bbd312f feat: Force UTF-8 encoding of input characters 2024-05-29 22:09:09 +02:00
Danny Lau
65b9544942 #1214 Fix unable to create FileMonitor if the root directory does not exist 2024-05-29 23:03:24 +08:00
albanobattistella
7e8b86e6eb Update messages_it_IT.properties 2024-05-29 12:08:25 +02:00
IT Creativity + Art Team
2ab5bc1e18 Update messages_bg_BG.properties
Updated/improved Bulgarian language strings. Thank you.
2024-05-29 09:56:21 +03:00
Dimitris Doukas
52e9689431 Merge branch 'Stirling-Tools:main' into main 2024-05-28 11:43:21 +03:00
Danny Lau
17ef2e9b5d Merge branch 'main' into bugfix/1214-grab-zero-byte-pdf 2024-05-25 08:20:57 +08:00
Danny Lau
801dcdb463 #1214 Only take files that are good for processing 2024-05-25 00:22:01 +08:00
Dimitris Doukas
caa5525ddd Merge branch 'Stirling-Tools:main' into main 2024-05-02 15:41:23 +03:00
648 changed files with 154378 additions and 3612 deletions

2
.gitattributes vendored
View File

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

116
.github/ISSUE_TEMPLATE/1-bug.yml vendored Normal file
View File

@@ -0,0 +1,116 @@
name: Bug Report
description: File a bug report.
title: "[Bug]: "
body:
- type: markdown
attributes:
value: |
## Bug Report
Thanks for taking the time to fill out this bug report!
This issue form is for reporting bugs only. Please fill out the following sections to help us understand the issue you are facing.
- type: textarea
id: problem
validations:
required: true
attributes:
label: The Problem
description: |
Describe the issue you are experiencing here. Tell us what you were trying to do and what happened.
Provide a clear and concise description of what the problem is.
placeholder: Provide a detailed description of the issue.
- type: markdown
attributes:
value: |
## Environment
- type: input
id: version
validations:
required: true
attributes:
label: Version of Stirling-PDF
placeholder: e.g., 0.0.2
description: What version of Stirling-PDF has the issue?
- type: input
id: last-working-version
attributes:
label: Last Working Version of Stirling-PDF
placeholder: e.g., 0.0.1
description: |
If known, please provide the last version where the issue did not occur. Otherwise, leave blank.
- type: input
id: url
attributes:
label: Page Where the Problem Occurred
placeholder: e.g., http://localhost:8080/pdf/pipeline
description: |
If applicable, provide the URL where the issue occurred. Otherwise, leave blank.
- type: textarea
id: docker
attributes:
label: Docker Configuration
description: |
Enter your Docker configuration here if it is relevant to the error. Remove any personal data. Otherwise, leave the field blank.
render: txt
- type: markdown
attributes:
value: |
## Logs
- type: textarea
id: logs
attributes:
label: Relevant Log Output
description: |
Provide any log output that might help us diagnose the issue, such as error messages or stack traces.
render: txt
- type: markdown
attributes:
value: |
## Additional Information
- type: textarea
id: additional-info
attributes:
label: Additional Information
description: |
If you have any additional information that might help us understand and resolve the issue, provide it here.
- type: markdown
attributes:
value: |
## Browser Information
- type: dropdown
id: browsers
attributes:
label: Browsers Affected
description: |
If applicable, select the browsers where you are experiencing the issue. Otherwise, leave blank.
multiple: true
options:
- Firefox
- Chrome
- Safari
- Microsoft Edge
- Other
- type: checkboxes
id: terms
attributes:
label: No Duplicate of the Issue
description: |
Please confirm that you have searched for similar issues and none of them match your problem.
options:
- label: I have verified that there are no existing issues raised related to my problem.
required: true

76
.github/ISSUE_TEMPLATE/2-feature.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: Feature Request
description: Submit a new feature request.
title: "[Feature Request]: "
body:
- type: markdown
attributes:
value: |
## Feature Request
Thank you for taking the time to suggest a new feature!
This form is for proposing features or enhancements. Please fill out the following sections to help us understand your idea or suggestion.
- type: textarea
id: feature-description
validations:
required: true
attributes:
label: Feature Description
description: |
Describe the feature you would like to see. Tell us what the feature should do and the problem it would solve.
Provide a clear and concise description of what you want to happen.
placeholder: Provide a detailed description of the desired feature.
- type: markdown
attributes:
value: |
## Motivation
- type: textarea
id: motivation
attributes:
label: Why is this feature valuable?
description: |
Explain why this feature is valuable to you or others. How would it improve the tool or process?
Describe any relevant scenarios that would benefit from this feature.
placeholder: Describe why this feature is important.
- type: markdown
attributes:
value: |
## Possible Implementation
- type: textarea
id: implementation
attributes:
label: Suggested Implementation
description: |
If you have ideas about how this feature could be implemented, describe them here.
This section is optional but can be helpful to guide initial discussions.
placeholder: Describe how this feature might be implemented.
- type: markdown
attributes:
value: |
## Additional Information
- type: textarea
id: additional-info
attributes:
label: Additional Information
description: |
If you have any additional information, comments, or resources you think would support or be relevant to your feature request, include them here.
- type: checkboxes
id: search-confirmation
attributes:
label: No Duplicate of the Feature
description: |
Please confirm that you have searched for similar features in our repository and found none that match your request.
options:
- label: I have verified that there are no existing features requests similar to my request.
required: true

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

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

View File

@@ -110,3 +110,31 @@ jobs:
labels: ${{ steps.meta2.outputs.labels }} labels: ${{ steps.meta2.outputs.labels }}
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8 platforms: linux/amd64,linux/arm64/v8
- name: Generate tags fat
id: meta3
uses: docker/metadata-action@v5
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 }}-fat,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest-fat,enable=${{ github.ref == 'refs/heads/master' }}
- name: Build and push main Dockerfile fat
uses: docker/build-push-action@v5
if: github.ref != 'refs/heads/main'
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile-fat
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ${{ steps.meta3.outputs.tags }}
labels: ${{ steps.meta3.outputs.labels }}
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8

84
Dockerfile-fat Normal file
View File

@@ -0,0 +1,84 @@
# Build the application
FROM gradle:8.7-jdk17 AS build
# Set the working directory
WORKDIR /app
# Copy the entire project to the working directory
COPY . .
# Build the application with DOCKER_ENABLE_SECURITY=false
RUN DOCKER_ENABLE_SECURITY=true \
./gradlew clean build
# Main stage
FROM alpine:3.20.0
# Copy necessary files
COPY scripts /scripts
COPY pipeline /pipeline
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
COPY --from=build /app/build/libs/*.jar app.jar
ARG VERSION_TAG
# Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \
VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
HOME=/home/stirlingpdfuser \
PUID=1000 \
PGID=1000 \
UMASK=022 \
FAT_DOCKER=true \
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=true
# JDK for app
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
apk upgrade --no-cache -a && \
apk add --no-cache \
ca-certificates \
tzdata \
tini \
bash \
curl \
calibre@testing \
shadow \
su-exec \
openssl \
openssl-dev \
openjdk21-jre \
# Doc conversion
libreoffice \
# pdftohtml
poppler-utils \
# OCR MY PDF (unpaper for descew and other advanced featues)
ocrmypdf \
tesseract-ocr-data-eng \
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
# CV
py3-opencv \
# python3/pip
python3 && \
wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \
# uno unoconv and HTML
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \
mv /usr/share/tessdata /usr/share/tessdata-original && \
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
fc-cache -f -v && \
chmod +x /scripts/* && \
chmod +x /scripts/init.sh && \
# User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
tesseract --list-langs
EXPOSE 8080/tcp
# Set user and run command
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

View File

@@ -1,46 +1,47 @@
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript | | Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------| | ------------------- | ------- | ------- | -------- | ----- | --- | ------ | ------ | ----------- | -------- | ---- | ---------- |
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ | | adjust-contrast | ✔️ | | | | | | | | | | ✔️ |
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | | | auto-split-pdf | ✔️ | | | | | | | | | ✔️ | |
| crop | ✔️ | | | | | | | | | ✔️ | | | crop | ✔️ | | | | | | | | | ✔️ | |
| extract-page | ✔️ | | | | | | | | | ✔️ | | | extract-page | ✔️ | | | | | | | | | ✔️ | |
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | | | merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | | | multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ | | pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | | | pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | |
| remove-pages | ✔️ | | | | | | | | | ✔️ | | | remove-pages | ✔️ | | | | | | | | | ✔️ | |
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | | | rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
| scale-pages | ✔️ | | | | | | | | | ✔️ | | | scale-pages | ✔️ | | | | | | | | | ✔️ | |
| split-pdfs | ✔️ | | | | | | | | | ✔️ | | | split-pdfs | ✔️ | | | | | | | | | ✔️ | |
| file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | | | file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | | | img-to-pdf | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | | | pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | | | pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | | | pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | |
| xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | | | xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| add-password | | | ✔️ | | | | | | | ✔️ | | | add-password | | | ✔️ | | | | | | | ✔️ | |
| add-watermark | | | ✔️ | | | | | | | ✔️ | | | add-watermark | | | ✔️ | | | | | | | ✔️ | |
| cert-sign | | | ✔️ | | | | | | | ✔️ | | | cert-sign | | | ✔️ | | | | | | | ✔️ | |
| change-permissions | | | ✔️ | | | | | | | ✔️ | | | remove-cert-sign | | | ✔️ | | | | | | | ✔️ | |
| remove-password | | | ✔️ | | | | | | | ✔️ | | | change-permissions | | | ✔️ | | | | | | | ✔️ | |
| sanitize-pdf | | | ✔️ | | | | | | | ✔️ | | | remove-password | | | ✔️ | | | | | | | ✔️ | |
| add-image | | | | ✔️ | | | | | | ✔️ | | | sanitize-pdf | | | ✔️ | | | | | | | ✔️ | |
| add-page-numbers | | | | ✔️ | | | | | | ✔️ | | | add-image | | | | ✔️ | | | | | | ✔️ | |
| auto-rename | | | | ✔️ | | | | | | ✔️ | | | add-page-numbers | | | | ✔️ | | | | | | ✔️ | |
| change-metadata | | | | ✔️ | | | | | | ✔️ | | | auto-rename | | | | ✔️ | | | | | | ✔️ | |
| compare | | | | ✔️ | | | | | | | ✔️ | | change-metadata | | | | ✔️ | | | | | | ✔️ | |
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | compare | | | | ✔️ | | | | | | | ✔️ |
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| extract-images | | | | ✔️ | | | | | | ✔️ | | | extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| flatten | | | | ✔️ | | | | | | | ✔️ | | extract-images | | | | ✔️ | | | | | | ✔️ | |
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | | | flatten | | | | ✔️ | | | | | | | ✔️ |
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | |
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | | | remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| show-javascript | | | | ✔️ | | | | | | | ✔️ | | repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
| sign | | | | ✔️ | | | | | | | ✔️ | | show-javascript | | | | ✔️ | | | | | | | ✔️ |
| sign | | | | ✔️ | | | | | | | ✔️ |

View File

@@ -159,39 +159,41 @@ Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR
## Supported Languages ## Supported Languages
Stirling PDF currently supports 28! Stirling PDF currently supports 32!
| Language | Progress | | Language | Progress |
| ------------------------------------------- | -------------------------------------- | | ------------------------------------------- | -------------------------------------- |
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) | | English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) | | English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| Arabic (العربية) (ar_AR) | ![41%](https://geps.dev/progress/41) | | Arabic (العربية) (ar_AR) | ![46%](https://geps.dev/progress/46) |
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) | | German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) | | French (Français) (fr_FR) | ![93%](https://geps.dev/progress/93) |
| Spanish (Español) (es_ES) | ![96%](https://geps.dev/progress/96) | | Spanish (Español) (es_ES) | ![93%](https://geps.dev/progress/93) |
| Simplified Chinese (简体中文) (zh_CN) | ![96%](https://geps.dev/progress/96) | | Simplified Chinese (简体中文) (zh_CN) | ![94%](https://geps.dev/progress/94) |
| Traditional Chinese (繁體中文) (zh_TW) | ![95%](https://geps.dev/progress/95) | | Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) |
| Catalan (Català) (ca_CA) | ![49%](https://geps.dev/progress/49) | | Catalan (Català) (ca_CA) | ![49%](https://geps.dev/progress/49) |
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) | | Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) |
| Swedish (Svenska) (sv_SE) | ![41%](https://geps.dev/progress/41) | | Swedish (Svenska) (sv_SE) | ![40%](https://geps.dev/progress/40) |
| Polish (Polski) (pl_PL) | ![43%](https://geps.dev/progress/43) | | Polish (Polski) (pl_PL) | ![42%](https://geps.dev/progress/42) |
| Romanian (Română) (ro_RO) | ![40%](https://geps.dev/progress/40) | | Romanian (Română) (ro_RO) | ![39%](https://geps.dev/progress/39) |
| Korean (한국어) (ko_KR) | ![88%](https://geps.dev/progress/88) | | Korean (한국어) (ko_KR) | ![86%](https://geps.dev/progress/86) |
| Portuguese Brazilian (Português) (pt_BR) | ![62%](https://geps.dev/progress/62) | | Portuguese Brazilian (Português) (pt_BR) | ![61%](https://geps.dev/progress/61) |
| Russian (Русский) (ru_RU) | ![88%](https://geps.dev/progress/88) | | Russian (Русский) (ru_RU) | ![86%](https://geps.dev/progress/86) |
| Basque (Euskara) (eu_ES) | ![64%](https://geps.dev/progress/64) | | Basque (Euskara) (eu_ES) | ![63%](https://geps.dev/progress/63) |
| Japanese (日本語) (ja_JP) | ![88%](https://geps.dev/progress/88) | | Japanese (日本語) (ja_JP) | ![86%](https://geps.dev/progress/86) |
| Dutch (Nederlands) (nl_NL) | ![86%](https://geps.dev/progress/86) | | Dutch (Nederlands) (nl_NL) | ![83%](https://geps.dev/progress/83) |
| Greek (Ελληνικά) (el_GR) | ![86%](https://geps.dev/progress/86) | | Greek (Ελληνικά) (el_GR) | ![84%](https://geps.dev/progress/84) |
| Turkish (Türkçe) (tr_TR) | ![98%](https://geps.dev/progress/98) | | Turkish (Türkçe) (tr_TR) | ![96%](https://geps.dev/progress/96) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![79%](https://geps.dev/progress/79) | | Indonesia (Bahasa Indonesia) (id_ID) | ![78%](https://geps.dev/progress/78) |
| Hindi (हिंदी) (hi_IN) | ![80%](https://geps.dev/progress/80) | | Hindi (हिंदी) (hi_IN) | ![79%](https://geps.dev/progress/79) |
| Hungarian (Magyar) (hu_HU) | ![79%](https://geps.dev/progress/79) | | Hungarian (Magyar) (hu_HU) | ![77%](https://geps.dev/progress/77) |
| Bulgarian (Български) (bg_BG) | ![96%](https://geps.dev/progress/96) | | Bulgarian (Български) (bg_BG) | ![96%](https://geps.dev/progress/96) |
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![81%](https://geps.dev/progress/81) | | Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![80%](https://geps.dev/progress/80) |
| Ukrainian (Українська) (uk_UA) | ![87%](https://geps.dev/progress/87) | | Ukrainian (Українська) (uk_UA) | ![85%](https://geps.dev/progress/85) |
| Slovakian (Slovensky) (sk_SK) | ![96%](https://geps.dev/progress/96) | | Slovakian (Slovensky) (sk_SK) | ![93%](https://geps.dev/progress/93) |
| Czech (Česky) (cs_CZ) | ![94%](https://geps.dev/progress/94) | | Czech (Česky) (cs_CZ) | ![92%](https://geps.dev/progress/92) |
| Croatian (Hrvatski) (hr_HR) | ![97%](https://geps.dev/progress/97) |
| Norwegian (Norsk) (no_NB) | ![97%](https://geps.dev/progress/97) |
## Contributing (creating issues, translations, fixing bugs, etc.) ## Contributing (creating issues, translations, fixing bugs, etc.)
@@ -213,10 +215,10 @@ For example in the settings.yml you have
```yaml ```yaml
system: system:
defaultLocale: 'en-US' enableLogin: 'true'
``` ```
To have this via an environment variable you would have ``SYSTEM_DEFAULTLOCALE`` To have this via an environment variable you would have ``SYSTEM_ENABLELOGIN``
The Current list of settings is The Current list of settings is

View File

@@ -1,52 +1,53 @@
| Technology | Ultra-Lite | Full | | Technology | Ultra-Lite | Full |
|----------------|:----------:|:----:| | ---------- | :--------: | :---: |
| Java | ✔️ | ✔️ | | Java | ✔️ | ✔️ |
| JavaScript | ✔️ | ✔️ | | JavaScript | ✔️ | ✔️ |
| Libre | | ✔️ | | Libre | | ✔️ |
| Python | | ✔️ | | Python | | ✔️ |
| OpenCV | | ✔️ | | OpenCV | | ✔️ |
| OCRmyPDF | | ✔️ | | OCRmyPDF | | ✔️ |
Operation | Ultra-Lite | Full | Operation | Ultra-Lite | Full |
-------------------------|------------|----- | ---------------------- | ---------- | ---- |
add-page-numbers | ✔️ | ✔️ | add-page-numbers | ✔️ | ✔️ |
add-password | ✔️ | ✔️ | add-password | ✔️ | ✔️ |
add-image | ✔️ | ✔️ | add-image | ✔️ | ✔️ |
add-watermark | ✔️ | ✔️ | add-watermark | ✔️ | ✔️ |
adjust-contrast | ✔️ | ✔️ | adjust-contrast | ✔️ | ✔️ |
auto-split-pdf | ✔️ | ✔️ | auto-split-pdf | ✔️ | ✔️ |
auto-redact | ✔️ | ✔️ | auto-redact | ✔️ | ✔️ |
auto-rename | ✔️ | ✔️ | auto-rename | ✔️ | ✔️ |
cert-sign | ✔️ | ✔️ | cert-sign | ✔️ | ✔️ |
crop | ✔️ | ✔️ | remove-cert-sign | ✔️ | ✔️ |
change-metadata | ✔️ | ✔️ | crop | ✔️ | ✔️ |
change-permissions | ✔️ | ✔️ | change-metadata | ✔️ | ✔️ |
compare | ✔️ | ✔️ | change-permissions | ✔️ | ✔️ |
extract-page | ✔️ | ✔️ | compare | ✔️ | ✔️ |
extract-images | ✔️ | ✔️ | extract-page | ✔️ | ✔️ |
flatten | ✔️ | ✔️ | extract-images | ✔️ | ✔️ |
get-info-on-pdf | ✔️ | ✔️ | flatten | ✔️ | ✔️ |
img-to-pdf | ✔️ | ✔️ | get-info-on-pdf | ✔️ | ✔️ |
markdown-to-pdf | ✔️ | ✔️ | img-to-pdf | ✔️ | ✔️ |
merge-pdfs | ✔️ | ✔️ | markdown-to-pdf | ✔️ | ✔️ |
multi-page-layout | ✔️ | ✔️ | merge-pdfs | ✔️ | ✔️ |
overlay-pdf | ✔️ | ✔️ | multi-page-layout | ✔️ | ✔️ |
pdf-organizer | ✔️ | ✔️ | overlay-pdf | ✔️ | ✔️ |
pdf-to-csv | ✔️ | ✔️ | pdf-organizer | ✔️ | ✔️ |
pdf-to-img | ✔️ | ✔️ | pdf-to-csv | ✔️ | ✔️ |
pdf-to-single-page | ✔️ | ✔️ | pdf-to-img | ✔️ | ✔️ |
remove-pages | ✔️ | ✔️ | pdf-to-single-page | ✔️ | ✔️ |
remove-password | ✔️ | ✔️ | remove-pages | ✔️ | ✔️ |
rotate-pdf | ✔️ | ✔️ | remove-password | ✔️ | ✔️ |
sanitize-pdf | ✔️ | ✔️ | rotate-pdf | ✔️ | ✔️ |
scale-pages | ✔️ | ✔️ | sanitize-pdf | ✔️ | ✔️ |
sign | ✔️ | ✔️ | scale-pages | ✔️ | ✔️ |
show-javascript | ✔️ | ✔️ | sign | ✔️ | ✔️ |
split-by-size-or-count | ✔️ | ✔️ | show-javascript | ✔️ | ✔️ |
split-pdf-by-sections | ✔️ | ✔️ | split-by-size-or-count | ✔️ | ✔️ |
split-pdfs | ✔️ | ✔️ | split-pdf-by-sections | ✔️ | ✔️ |
compress-pdf | | ✔️ | split-pdfs | ✔️ | ✔️ |
extract-image-scans | | ✔️ | compress-pdf | | ✔️ |
ocr-pdf | | ✔️ | extract-image-scans | | ✔️ |
pdf-to-pdfa | | ✔️ | ocr-pdf | | ✔️ |
remove-blanks | | ✔️ | pdf-to-pdfa | | ✔️ |
| remove-blanks | | ✔️ |

View File

@@ -12,7 +12,7 @@ plugins {
import com.github.jk1.license.render.* import com.github.jk1.license.render.*
group = 'stirling.software' group = 'stirling.software'
version = '0.25.0' version = '0.26.1'
//17 is lowest but we support and recommend 21 //17 is lowest but we support and recommend 21
sourceCompatibility = '17' sourceCompatibility = '17'
@@ -21,7 +21,6 @@ repositories {
mavenCentral() mavenCentral()
} }
licenseReport { licenseReport {
renderers = [new JsonReportRenderer()] renderers = [new JsonReportRenderer()]
} }
@@ -136,7 +135,7 @@ dependencies {
implementation 'com.twelvemonkeys.imageio:imageio-webp:3.10.1' implementation 'com.twelvemonkeys.imageio:imageio-webp:3.10.1'
// implementation 'com.twelvemonkeys.imageio:imageio-xwd:3.10.1' // implementation 'com.twelvemonkeys.imageio:imageio-xwd:3.10.1'
implementation 'commons-io:commons-io:2.15.1' implementation 'commons-io:commons-io:2.16.1'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
//general PDF //general PDF
@@ -172,14 +171,14 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok:1.18.32' annotationProcessor 'org.projectlombok:lombok:1.18.32'
} }
tasks.withType(JavaCompile) { tasks.withType(JavaCompile).configureEach {
dependsOn 'spotlessApply' dependsOn 'spotlessApply'
} }
compileJava { compileJava {
options.compilerArgs << '-parameters' options.compilerArgs << '-parameters'
} }
task writeVersion { task writeVersion {
def propsFile = file('src/main/resources/version.properties') def propsFile = file('src/main/resources/version.properties')
def props = new Properties() def props = new Properties()
props.setProperty('version', version) props.setProperty('version', version)
@@ -196,8 +195,6 @@ swaggerhubUpload {
oas '3.0.0' // The version of the OpenAPI Specification you're using oas '3.0.0' // The version of the OpenAPI Specification you're using
} }
jar { jar {
enabled = false enabled = false
manifest { manifest {
@@ -211,6 +208,6 @@ tasks.named('test') {
useJUnitPlatform() useJUnitPlatform()
} }
task printVersion { task printVersion {
println project.version println project.version
} }

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 50 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

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

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,34 @@
version: '3.3'
services:
stirling-pdf:
container_name: Stirling-PDF-Security-Fat
image: frooodle/s-pdf:latest-fat
deploy:
resources:
limits:
memory: 4G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true"
PUID: 1002
PGID: 1002
UMASK: "022"
SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with Security
UI_APPNAMENAVBAR: Stirling-PDF Latest-fat
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
restart: on-failure:5

View File

@@ -13,7 +13,7 @@ services:
timeout: 10s timeout: 10s
retries: 16 retries: 16
ports: ports:
- 8080:8080 - "8080:8080"
volumes: volumes:
- /stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
@@ -27,6 +27,8 @@ services:
SECURITY_OAUTH2_CLIENTID: "<YOUR CLIENT ID>.apps.googleusercontent.com" # Client ID from your provider SECURITY_OAUTH2_CLIENTID: "<YOUR CLIENT ID>.apps.googleusercontent.com" # Client ID from your provider
SECURITY_OAUTH2_CLIENTSECRET: "<YOUR CLIENT SECRET>" # Client Secret from your provider SECURITY_OAUTH2_CLIENTSECRET: "<YOUR CLIENT SECRET>" # Client Secret from your provider
SECURITY_OAUTH2_SCOPES: "openid,profile,email" # Expected OAuth2 Scope SECURITY_OAUTH2_SCOPES: "openid,profile,email" # Expected OAuth2 Scope
SECURITY_OAUTH2_USEASUSERNAME: "email" # Default is 'email'; custom fields can be used as the username
SECURITY_OAUTH2_PROVIDER: "google" # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
PUID: 1002 PUID: 1002
PGID: 1002 PGID: 1002
UMASK: "022" UMASK: "022"

View File

@@ -13,7 +13,7 @@ services:
timeout: 10s timeout: 10s
retries: 16 retries: 16
ports: ports:
- 8080:8080 - "8080:8080"
volumes: volumes:
- /stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw

View File

@@ -13,7 +13,7 @@ services:
timeout: 10s timeout: 10s
retries: 16 retries: 16
ports: ports:
- 8080:8080 - "8080:8080"
volumes: volumes:
- /stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw

View File

@@ -13,7 +13,7 @@ services:
timeout: 10s timeout: 10s
retries: 16 retries: 16
ports: ports:
- 8080:8080 - "8080:8080"
volumes: volumes:
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw

View File

@@ -13,7 +13,7 @@ services:
timeout: 10s timeout: 10s
retries: 16 retries: 16
ports: ports:
- 8080:8080 - "8080:8080"
volumes: volumes:
- /stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
images/settings-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 145 KiB

View File

@@ -0,0 +1,43 @@
{
"name": "OCR images",
"pipeline": [
{
"operation": "/api/v1/convert/img/pdf",
"parameters": {
"fitOption": "fillPage",
"colorType": "color",
"autoRotate": true,
"fileInput": "automated"
}
},
{
"operation": "/api/v1/general/merge-pdfs",
"parameters": {
"sortType": "orderProvided",
"fileInput": "automated"
}
},
{
"operation": "/api/v1/misc/ocr-pdf",
"parameters": {
"languages": [
"eng"
],
"sidecar": false,
"deskew": false,
"clean": false,
"cleanFinal": false,
"ocrType": "skip-text",
"ocrRenderType": "hocr",
"removeImagesAfter": false,
"fileInput": "automated"
}
}
],
"_examples": {
"outputDir": "{outputFolder}/{folderName}",
"outputFileName": "{filename}-{pipelineName}-{date}-{time}"
},
"outputDir": "{outputFolder}",
"outputFileName": "{filename}"
}

View File

@@ -11,14 +11,16 @@ if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -
fi fi
umask "$UMASK" || true umask "$UMASK" || true
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" && "$FAT_DOCKER" != "true" ]]; then
apk add --no-cache calibre@testing apk add --no-cache calibre@testing
fi fi
/scripts/download-security-jar.sh if [[ "$FAT_DOCKER" != "true" ]]; then
/scripts/download-security-jar.sh
fi
if [[ -n "$LANGS" ]]; then if [[ -n "$LANGS" ]]; then
/scripts/installFonts.sh $LANGS /scripts/installFonts.sh $LANGS
fi fi
echo "Setting permissions and ownership for necessary directories..." echo "Setting permissions and ownership for necessary directories..."

View File

@@ -15,7 +15,10 @@ ignore = [
[cs_CZ] [cs_CZ]
ignore = [ ignore = [
'info',
'language.direction', 'language.direction',
'pipeline.header',
'text',
] ]
[de_DE] [de_DE]
@@ -58,6 +61,7 @@ ignore = [
[fr_FR] [fr_FR]
ignore = [ ignore = [
'language.direction', 'language.direction',
'sponsor',
] ]
[hi_IN] [hi_IN]
@@ -65,6 +69,16 @@ ignore = [
'language.direction', 'language.direction',
] ]
[hr_HR]
ignore = [
'font',
'home.pipeline.title',
'info',
'language.direction',
'pdfOrganiser.tags',
'showJS.tags',
]
[hu_HU] [hu_HU]
ignore = [ ignore = [
'language.direction', 'language.direction',
@@ -103,6 +117,11 @@ ignore = [
'language.direction', 'language.direction',
] ]
[no_NB]
ignore = [
'language.direction',
]
[pl_PL] [pl_PL]
ignore = [ ignore = [
'language.direction', 'language.direction',

View File

@@ -6,11 +6,15 @@ import java.net.Socket;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.github.pixee.security.SystemCommand; import io.github.pixee.security.SystemCommand;
public class LibreOfficeListener { public class LibreOfficeListener {
private static final long ACTIVITY_TIMEOUT = 20 * 60 * 1000; // 20 minutes private static final Logger logger = LoggerFactory.getLogger(LibreOfficeListener.class);
private static final long ACTIVITY_TIMEOUT = 20L * 60 * 1000; // 20 minutes
private static final LibreOfficeListener INSTANCE = new LibreOfficeListener(); private static final LibreOfficeListener INSTANCE = new LibreOfficeListener();
private static final int LISTENER_PORT = 2002; private static final int LISTENER_PORT = 2002;
@@ -27,14 +31,12 @@ public class LibreOfficeListener {
private LibreOfficeListener() {} private LibreOfficeListener() {}
private boolean isListenerRunning() { private boolean isListenerRunning() {
try { System.out.println("waiting for listener to start");
System.out.println("waiting for listener to start"); try (Socket socket = new Socket()) {
Socket socket = new Socket();
socket.connect( socket.connect(
new InetSocketAddress("localhost", 2002), 1000); // Timeout after 1 second new InetSocketAddress("localhost", 2002), 1000); // Timeout after 1 second
socket.close();
return true; return true;
} catch (IOException e) { } catch (Exception e) {
return false; return false;
} }
} }
@@ -63,6 +65,7 @@ public class LibreOfficeListener {
try { try {
Thread.sleep(5000); // Check for inactivity every 5 seconds Thread.sleep(5000); // Check for inactivity every 5 seconds
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt();
break; break;
} }
} }
@@ -80,8 +83,8 @@ public class LibreOfficeListener {
try { try {
Thread.sleep(1000); Thread.sleep(1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// TODO Auto-generated catch block Thread.currentThread().interrupt();
e.printStackTrace(); logger.error("exception", e);
} // Check every 1 second } // Check every 1 second
} }
} }

View File

@@ -2,9 +2,13 @@ package stirling.software.SPDF.config;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Properties; import java.util.Properties;
import java.util.function.Predicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -22,6 +26,8 @@ import stirling.software.SPDF.model.ApplicationProperties;
@Lazy @Lazy
public class AppConfig { public class AppConfig {
private static final Logger logger = LoggerFactory.getLogger(AppConfig.class);
@Autowired ApplicationProperties applicationProperties; @Autowired ApplicationProperties applicationProperties;
@Bean @Bean
@@ -54,7 +60,7 @@ public class AppConfig {
props.load(resource.getInputStream()); props.load(resource.getInputStream());
return props.getProperty("version"); return props.getProperty("version");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
return "0.0.0"; return "0.0.0";
} }
@@ -108,4 +114,26 @@ public class AppConfig {
public boolean missingActivSecurity() { public boolean missingActivSecurity() {
return false; return false;
} }
@Bean(name = "watchedFoldersDir")
public String watchedFoldersDir() {
return "./pipeline/watchedFolders/";
}
@Bean(name = "finishedFoldersDir")
public String finishedFoldersDir() {
return "./pipeline/finishedFolders/";
}
@Bean(name = "directoryFilter")
public Predicate<Path> processPDFOnlyFilter() {
return path -> {
if (Files.isDirectory(path)) {
return !path.toString().contains("processing");
} else {
String fileName = path.getFileName().toString();
return fileName.endsWith(".pdf");
}
};
}
} }

View File

@@ -58,7 +58,8 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
// Redirect to the URL with only allowed query parameters // Redirect to the URL with only allowed query parameters
String redirectUrl = requestURI + "?" + newQueryString; String redirectUrl = requestURI + "?" + newQueryString;
response.sendRedirect(redirectUrl);
response.sendRedirect(request.getContextPath() + redirectUrl);
return false; return false;
} }
} }

View File

@@ -7,7 +7,6 @@ import java.net.URISyntaxException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
@@ -45,46 +44,47 @@ public class ConfigInitializer
} }
} }
} else { } else {
Path templatePath = // Path templatePath =
Paths.get( // Paths.get(
getClass() // getClass()
.getClassLoader() // .getClassLoader()
.getResource("settings.yml.template") // .getResource("settings.yml.template")
.toURI()); // .toURI());
Path userPath = Paths.get("configs", "settings.yml"); // Path userPath = Paths.get("configs", "settings.yml");
//
List<String> templateLines = Files.readAllLines(templatePath); // List<String> templateLines = Files.readAllLines(templatePath);
List<String> userLines = // List<String> userLines =
Files.exists(userPath) ? Files.readAllLines(userPath) : new ArrayList<>(); // Files.exists(userPath) ? Files.readAllLines(userPath) : new
// ArrayList<>();
List<String> resultLines = new ArrayList<>(); //
int position = 0; // List<String> resultLines = new ArrayList<>();
for (String templateLine : templateLines) { // int position = 0;
// Check if the line is a comment // for (String templateLine : templateLines) {
if (templateLine.trim().startsWith("#")) { // // Check if the line is a comment
String entry = templateLine.trim().substring(1).trim(); // if (templateLine.trim().startsWith("#")) {
if (!entry.isEmpty()) { // String entry = templateLine.trim().substring(1).trim();
// Check if this comment has been uncommented in userLines // if (!entry.isEmpty()) {
String key = entry.split(":")[0].trim(); // // Check if this comment has been uncommented in userLines
addLine(resultLines, userLines, templateLine, key, position); // String key = entry.split(":")[0].trim();
} else { // addLine(resultLines, userLines, templateLine, key, position);
resultLines.add(templateLine); // } else {
} // resultLines.add(templateLine);
} // }
// Check if the line is a key-value pair // }
else if (templateLine.contains(":")) { // // Check if the line is a key-value pair
String key = templateLine.split(":")[0].trim(); // else if (templateLine.contains(":")) {
addLine(resultLines, userLines, templateLine, key, position); // String key = templateLine.split(":")[0].trim();
} // addLine(resultLines, userLines, templateLine, key, position);
// Handle empty lines // }
else if (templateLine.trim().length() == 0) { // // Handle empty lines
resultLines.add(""); // else if (templateLine.trim().length() == 0) {
} // resultLines.add("");
position++; // }
} // position++;
// }
// Write the result to the user settings file //
Files.write(userPath, resultLines); // // Write the result to the user settings file
// Files.write(userPath, resultLines);
} }
Path customSettingsPath = Paths.get("configs", "custom_settings.yml"); Path customSettingsPath = Paths.get("configs", "custom_settings.yml");

View File

@@ -116,6 +116,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Security", "change-permissions"); addEndpointToGroup("Security", "change-permissions");
addEndpointToGroup("Security", "add-watermark"); addEndpointToGroup("Security", "add-watermark");
addEndpointToGroup("Security", "cert-sign"); addEndpointToGroup("Security", "cert-sign");
addEndpointToGroup("Security", "remove-cert-sign");
addEndpointToGroup("Security", "sanitize-pdf"); addEndpointToGroup("Security", "sanitize-pdf");
addEndpointToGroup("Security", "auto-redact"); addEndpointToGroup("Security", "auto-redact");
@@ -200,6 +201,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "extract-images"); addEndpointToGroup("Java", "extract-images");
addEndpointToGroup("Java", "change-metadata"); addEndpointToGroup("Java", "change-metadata");
addEndpointToGroup("Java", "cert-sign"); addEndpointToGroup("Java", "cert-sign");
addEndpointToGroup("Java", "remove-cert-sign");
addEndpointToGroup("Java", "multi-page-layout"); addEndpointToGroup("Java", "multi-page-layout");
addEndpointToGroup("Java", "scale-pages"); addEndpointToGroup("Java", "scale-pages");
addEndpointToGroup("Java", "add-page-numbers"); addEndpointToGroup("Java", "add-page-numbers");

View File

@@ -1,16 +1,18 @@
package stirling.software.SPDF.config; package stirling.software.SPDF.config;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Map; import java.util.Map;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.thymeleaf.IEngineConfiguration; import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver; import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
import org.thymeleaf.templateresource.ClassLoaderTemplateResource;
import org.thymeleaf.templateresource.FileTemplateResource; import org.thymeleaf.templateresource.FileTemplateResource;
import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.ITemplateResource;
import stirling.software.SPDF.model.InputStreamTemplateResource;
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver { public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
private final ResourceLoader resourceLoader; private final ResourceLoader resourceLoader;
@@ -40,9 +42,13 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe
} }
return new ClassLoaderTemplateResource( InputStream inputStream =
Thread.currentThread().getContextClassLoader(), Thread.currentThread()
"classpath:/templates/" + resourceName, .getContextClassLoader()
characterEncoding); .getResourceAsStream("templates/" + resourceName);
if (inputStream != null) {
return new InputStreamTemplateResource(inputStream, "UTF-8");
}
return null;
} }
} }

View File

@@ -36,7 +36,6 @@ public class MetricsFilter extends OncePerRequestFilter {
|| uri.startsWith("/v1/api-docs") || uri.startsWith("/v1/api-docs")
|| uri.endsWith("robots.txt") || uri.endsWith("robots.txt")
|| uri.startsWith("/images") || uri.startsWith("/images")
|| uri.startsWith("/images")
|| uri.endsWith(".png") || uri.endsWith(".png")
|| uri.endsWith(".ico") || uri.endsWith(".ico")
|| uri.endsWith(".css") || uri.endsWith(".css")

View File

@@ -18,6 +18,7 @@ class AppUpdateAuthService implements ShowAdminInterface {
@Autowired private UserRepository userRepository; @Autowired private UserRepository userRepository;
@Autowired private ApplicationProperties applicationProperties; @Autowired private ApplicationProperties applicationProperties;
@Override
public boolean getShowUpdateOnlyAdmins() { public boolean getShowUpdateOnlyAdmins() {
boolean showUpdate = applicationProperties.getSystem().getShowUpdate(); boolean showUpdate = applicationProperties.getSystem().getShowUpdate();
if (!showUpdate) { if (!showUpdate) {

View File

@@ -42,36 +42,39 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
String ip = request.getRemoteAddr(); String ip = request.getRemoteAddr();
logger.error("Failed login attempt from IP: {}", ip); logger.error("Failed login attempt from IP: {}", ip);
String contextPath = request.getContextPath();
if (exception.getClass().isAssignableFrom(InternalAuthenticationServiceException.class) if (exception.getClass().isAssignableFrom(InternalAuthenticationServiceException.class)
|| "Password must not be null".equalsIgnoreCase(exception.getMessage())) { || "Password must not be null".equalsIgnoreCase(exception.getMessage())) {
response.sendRedirect("/login?error=oauth2AuthenticationError"); response.sendRedirect(contextPath + "/login?error=oauth2AuthenticationError");
return; return;
} }
String username = request.getParameter("username"); String username = request.getParameter("username");
if (username != null && !isDemoUser(username)) { Optional<User> optUser = userService.findByUsernameIgnoreCase(username);
if (username != null && optUser.isPresent() && !isDemoUser(optUser)) {
logger.info( logger.info(
"Remaining attempts for user {}: {}", "Remaining attempts for user {}: {}",
username, optUser.get().getUsername(),
loginAttemptService.getRemainingAttempts(username)); loginAttemptService.getRemainingAttempts(username));
loginAttemptService.loginFailed(username); loginAttemptService.loginFailed(username);
if (loginAttemptService.isBlocked(username) if (loginAttemptService.isBlocked(username)
|| exception.getClass().isAssignableFrom(LockedException.class)) { || exception.getClass().isAssignableFrom(LockedException.class)) {
response.sendRedirect("/login?error=locked"); response.sendRedirect(contextPath + "/login?error=locked");
return; return;
} }
} }
if (exception.getClass().isAssignableFrom(BadCredentialsException.class) if (exception.getClass().isAssignableFrom(BadCredentialsException.class)
|| exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) { || exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) {
response.sendRedirect("/login?error=badcredentials"); response.sendRedirect(contextPath + "/login?error=badcredentials");
return; return;
} }
super.onAuthenticationFailure(request, response, exception); super.onAuthenticationFailure(request, response, exception);
} }
private boolean isDemoUser(String username) { private boolean isDemoUser(Optional<User> user) {
Optional<User> user = userService.findByUsernameIgnoreCase(username);
return user.isPresent() return user.isPresent()
&& user.get().getAuthorities().stream() && user.get().getAuthorities().stream()
.anyMatch(authority -> "ROLE_DEMO_USER".equals(authority.getAuthority())); .anyMatch(authority -> "ROLE_DEMO_USER".equals(authority.getAuthority()));

View File

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

View File

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

View File

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

View File

@@ -33,7 +33,6 @@ public class LoginAttemptService {
} }
public void loginSucceeded(String key) { public void loginSucceeded(String key) {
logger.info(key + " " + attemptsCache.mappingCount());
if (key == null || key.trim().isEmpty()) { if (key == null || key.trim().isEmpty()) {
return; return;
} }

View File

@@ -238,7 +238,7 @@ public class SecurityConfiguration {
GoogleProvider google = client.getGoogle(); GoogleProvider google = client.getGoogle();
return google != null && google.isSettingsValid() return google != null && google.isSettingsValid()
? Optional.of( ? Optional.of(
ClientRegistration.withRegistrationId("google") ClientRegistration.withRegistrationId(google.getName())
.clientId(google.getClientId()) .clientId(google.getClientId())
.clientSecret(google.getClientSecret()) .clientSecret(google.getClientSecret())
.scope(google.getScopes()) .scope(google.getScopes())
@@ -246,8 +246,8 @@ public class SecurityConfiguration {
.tokenUri(google.getTokenuri()) .tokenUri(google.getTokenuri())
.userInfoUri(google.getUserinfouri()) .userInfoUri(google.getUserinfouri())
.userNameAttributeName(google.getUseAsUsername()) .userNameAttributeName(google.getUseAsUsername())
.clientName("Google") .clientName(google.getClientName())
.redirectUri("{baseUrl}/login/oauth2/code/google") .redirectUri("{baseUrl}/login/oauth2/code/" + google.getName())
.authorizationGrantType( .authorizationGrantType(
org.springframework.security.oauth2.core org.springframework.security.oauth2.core
.AuthorizationGrantType.AUTHORIZATION_CODE) .AuthorizationGrantType.AUTHORIZATION_CODE)
@@ -269,12 +269,12 @@ public class SecurityConfiguration {
return keycloak != null && keycloak.isSettingsValid() return keycloak != null && keycloak.isSettingsValid()
? Optional.of( ? Optional.of(
ClientRegistrations.fromIssuerLocation(keycloak.getIssuer()) ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())
.registrationId("keycloak") .registrationId(keycloak.getName())
.clientId(keycloak.getClientId()) .clientId(keycloak.getClientId())
.clientSecret(keycloak.getClientSecret()) .clientSecret(keycloak.getClientSecret())
.scope(keycloak.getScopes()) .scope(keycloak.getScopes())
.userNameAttributeName(keycloak.getUseAsUsername()) .userNameAttributeName(keycloak.getUseAsUsername())
.clientName("Keycloak") .clientName(keycloak.getClientName())
.build()) .build())
: Optional.empty(); : Optional.empty();
} }
@@ -291,7 +291,7 @@ public class SecurityConfiguration {
GithubProvider github = client.getGithub(); GithubProvider github = client.getGithub();
return github != null && github.isSettingsValid() return github != null && github.isSettingsValid()
? Optional.of( ? Optional.of(
ClientRegistration.withRegistrationId("github") ClientRegistration.withRegistrationId(github.getName())
.clientId(github.getClientId()) .clientId(github.getClientId())
.clientSecret(github.getClientSecret()) .clientSecret(github.getClientSecret())
.scope(github.getScopes()) .scope(github.getScopes())
@@ -299,8 +299,8 @@ public class SecurityConfiguration {
.tokenUri(github.getTokenuri()) .tokenUri(github.getTokenuri())
.userInfoUri(github.getUserinfouri()) .userInfoUri(github.getUserinfouri())
.userNameAttributeName(github.getUseAsUsername()) .userNameAttributeName(github.getUseAsUsername())
.clientName("GitHub") .clientName(github.getClientName())
.redirectUri("{baseUrl}/login/oauth2/code/github") .redirectUri("{baseUrl}/login/oauth2/code/" + github.getName())
.authorizationGrantType( .authorizationGrantType(
org.springframework.security.oauth2.core org.springframework.security.oauth2.core
.AuthorizationGrantType.AUTHORIZATION_CODE) .AuthorizationGrantType.AUTHORIZATION_CODE)

View File

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

View File

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

View File

@@ -52,7 +52,7 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
issuer = provider.getIssuer(); issuer = provider.getIssuer();
clientId = provider.getClientId(); clientId = provider.getClientId();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("exception", e);
} }
} else { } else {
@@ -60,13 +60,13 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
issuer = oauth.getIssuer(); issuer = oauth.getIssuer();
clientId = oauth.getClientId(); clientId = oauth.getClientId();
} }
String errorMessage = "";
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) { if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
param = "erroroauth=oauth2AuthenticationErrorWeb"; param = "erroroauth=oauth2AuthenticationErrorWeb";
} else if (request.getParameter("error") != null) { } else if ((errorMessage = request.getParameter("error")) != null) {
param = "error=" + request.getParameter("error"); param = "error=" + sanitizeInput(errorMessage);
} else if (request.getParameter("erroroauth") != null) { } else if ((errorMessage = request.getParameter("erroroauth")) != null) {
param = "erroroauth=" + request.getParameter("erroroauth"); param = "erroroauth=" + sanitizeInput(errorMessage);
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) { } else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
param = "error=oauth2AutoCreateDisabled"; param = "error=oauth2AutoCreateDisabled";
} }
@@ -81,7 +81,7 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
logger.info("Session invalidated: " + sessionId); logger.info("Session invalidated: " + sessionId);
} }
switch (registrationId) { switch (registrationId.toLowerCase()) {
case "keycloak": case "keycloak":
// Add Keycloak specific logout URL if needed // Add Keycloak specific logout URL if needed
String logoutUrl = String logoutUrl =
@@ -115,4 +115,8 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
break; break;
} }
} }
private String sanitizeInput(String input) {
return input.replaceAll("[^a-zA-Z0-9 ]", "");
}
} }

View File

@@ -16,6 +16,8 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import stirling.software.SPDF.config.security.LoginAttemptService; import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> { public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
@@ -41,11 +43,27 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
@Override @Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException { public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
String usernameAttribute = OAUTH2 oauth2 = applicationProperties.getSecurity().getOAUTH2();
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername(); String usernameAttribute = oauth2.getUseAsUsername();
if (usernameAttribute == null || usernameAttribute.trim().isEmpty()) {
Client client = oauth2.getClient();
if (client != null && client.getKeycloak() != null) {
usernameAttribute = client.getKeycloak().getUseAsUsername();
} else {
usernameAttribute = "email";
}
}
try { try {
OidcUser user = delegate.loadUser(userRequest); OidcUser user = delegate.loadUser(userRequest);
String username = user.getUserInfo().getClaimAsString(usernameAttribute); String username = user.getUserInfo().getClaimAsString(usernameAttribute);
// Check if the username claim is null or empty
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException(
"Claim '" + usernameAttribute + "' cannot be null or empty");
}
Optional<User> duser = userService.findByUsernameIgnoreCase(username); Optional<User> duser = userService.findByUsernameIgnoreCase(username);
if (duser.isPresent()) { if (duser.isPresent()) {
if (loginAttemptService.isBlocked(username)) { if (loginAttemptService.isBlocked(username)) {
@@ -56,13 +74,14 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
throw new IllegalArgumentException("Password must not be null"); throw new IllegalArgumentException("Password must not be null");
} }
} }
// Return a new OidcUser with adjusted attributes // Return a new OidcUser with adjusted attributes
return new DefaultOidcUser( return new DefaultOidcUser(
user.getAuthorities(), user.getAuthorities(),
userRequest.getIdToken(), userRequest.getIdToken(),
user.getUserInfo(), user.getUserInfo(),
usernameAttribute); usernameAttribute);
} catch (java.lang.IllegalArgumentException e) { } catch (IllegalArgumentException e) {
logger.error("Error loading OIDC user: {}", e.getMessage()); logger.error("Error loading OIDC user: {}", e.getMessage());
throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e); throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -10,11 +10,16 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
import org.apache.pdfbox.multipdf.PDFMergerUtility; import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -38,6 +43,7 @@ public class MergeController {
private static final Logger logger = LoggerFactory.getLogger(MergeController.class); private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
// Merges a list of PDDocument objects into a single PDDocument
public PDDocument mergeDocuments(List<PDDocument> documents) throws IOException { public PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
PDDocument mergedDoc = new PDDocument(); PDDocument mergedDoc = new PDDocument();
for (PDDocument doc : documents) { for (PDDocument doc : documents) {
@@ -48,6 +54,7 @@ public class MergeController {
return mergedDoc; return mergedDoc;
} }
// Returns a comparator for sorting MultipartFile arrays based on the given sort type
private Comparator<MultipartFile> getSortComparator(String sortType) { private Comparator<MultipartFile> getSortComparator(String sortType) {
switch (sortType) { switch (sortType) {
case "byFileName": case "byFileName":
@@ -108,37 +115,78 @@ public class MergeController {
"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") "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(@ModelAttribute MergePdfsRequest form) public ResponseEntity<byte[]> mergePdfs(@ModelAttribute MergePdfsRequest form)
throws IOException { throws IOException {
List<File> filesToDelete = new ArrayList<File>(); List<File> filesToDelete = new ArrayList<>(); // List of temporary files to delete
ByteArrayOutputStream docOutputstream =
new ByteArrayOutputStream(); // Stream for the merged document
PDDocument mergedDocument = null;
boolean removeCertSign = form.isRemoveCertSign();
try { try {
MultipartFile[] files = form.getFileInput(); MultipartFile[] files = form.getFileInput();
Arrays.sort(files, getSortComparator(form.getSortType())); Arrays.sort(
files,
PDFMergerUtility mergedDoc = new PDFMergerUtility(); getSortComparator(
ByteArrayOutputStream docOutputstream = new ByteArrayOutputStream(); form.getSortType())); // Sort files based on the given sort type
PDFMergerUtility mergerUtility = new PDFMergerUtility();
for (MultipartFile multipartFile : files) { for (MultipartFile multipartFile : files) {
File tempFile = GeneralUtils.convertMultipartFileToFile(multipartFile); File tempFile =
filesToDelete.add(tempFile); GeneralUtils.convertMultipartFileToFile(
mergedDoc.addSource(tempFile); multipartFile); // Convert MultipartFile to File
filesToDelete.add(tempFile); // Add temp file to the list for later deletion
mergerUtility.addSource(tempFile); // Add source file to the merger utility
}
mergerUtility.setDestinationStream(
docOutputstream); // Set the output stream for the merged document
mergerUtility.mergeDocuments(null); // Merge the documents
byte[] mergedPdfBytes = docOutputstream.toByteArray(); // Get merged document bytes
// Load the merged PDF document
mergedDocument = Loader.loadPDF(mergedPdfBytes);
// Remove signatures if removeCertSign is true
if (removeCertSign) {
PDDocumentCatalog catalog = mergedDocument.getDocumentCatalog();
PDAcroForm acroForm = catalog.getAcroForm();
if (acroForm != null) {
List<PDField> fieldsToRemove =
acroForm.getFields().stream()
.filter(field -> field instanceof PDSignatureField)
.collect(Collectors.toList());
if (!fieldsToRemove.isEmpty()) {
acroForm.flatten(
fieldsToRemove,
false); // Flatten the fields, effectively removing them
}
}
} }
mergedDoc.setDestinationFileName( // Save the modified document to a new ByteArrayOutputStream
files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf"); ByteArrayOutputStream baos = new ByteArrayOutputStream();
mergedDoc.setDestinationStream(docOutputstream); mergedDocument.save(baos);
mergedDoc.mergeDocuments(null);
String mergedFileName =
files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "")
+ "_merged_unsigned.pdf";
return WebResponseUtils.bytesToWebResponse( return WebResponseUtils.bytesToWebResponse(
docOutputstream.toByteArray(), mergedDoc.getDestinationFileName()); baos.toByteArray(), mergedFileName); // Return the modified PDF
} catch (Exception ex) { } catch (Exception ex) {
logger.error("Error in merge pdf process", ex); logger.error("Error in merge pdf process", ex);
throw ex; throw ex;
} finally { } finally {
for (File file : filesToDelete) { for (File file : filesToDelete) {
if (file != null) { if (file != null) {
Files.deleteIfExists(file.toPath()); Files.deleteIfExists(file.toPath()); // Delete temporary files
} }
} }
docOutputstream.close();
if (mergedDocument != null) {
mergedDocument.close(); // Close the merged document
}
} }
} }
} }

View File

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

View File

@@ -18,6 +18,8 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@@ -38,6 +40,9 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "General", description = "General APIs") @Tag(name = "General", description = "General APIs")
public class SplitPdfBySectionsController { public class SplitPdfBySectionsController {
private static final Logger logger =
LoggerFactory.getLogger(SplitPdfBySectionsController.class);
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data") @PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
@Operation( @Operation(
summary = "Split PDF pages into smaller sections", summary = "Split PDF pages into smaller sections",
@@ -92,7 +97,7 @@ public class SplitPdfBySectionsController {
if (sectionNum == horiz * verti) pageNum++; if (sectionNum == horiz * verti) pageNum++;
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("exception", e);
} finally { } finally {
data = Files.readAllBytes(zipFile); data = Files.readAllBytes(zipFile);
Files.deleteIfExists(zipFile); Files.deleteIfExists(zipFile);

View File

@@ -10,6 +10,8 @@ import java.util.zip.ZipOutputStream;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@@ -31,6 +33,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "General", description = "General APIs") @Tag(name = "General", description = "General APIs")
public class SplitPdfBySizeController { public class SplitPdfBySizeController {
private static final Logger logger = LoggerFactory.getLogger(SplitPdfBySizeController.class);
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data") @PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
@Operation( @Operation(
summary = "Auto split PDF pages into separate documents based on size or count", summary = "Auto split PDF pages into separate documents based on size or count",
@@ -66,7 +70,7 @@ public class SplitPdfBySizeController {
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("exception", e);
} finally { } finally {
data = Files.readAllBytes(zipFile); data = Files.readAllBytes(zipFile);
Files.deleteIfExists(zipFile); Files.deleteIfExists(zipFile);

View File

@@ -59,53 +59,53 @@ public class UserController {
@PostMapping("/change-username") @PostMapping("/change-username")
public RedirectView changeUsername( public RedirectView changeUsername(
Principal principal, Principal principal,
@RequestParam(name = "currentPassword") String currentPassword, @RequestParam(name = "currentPasswordChangeUsername") String currentPassword,
@RequestParam(name = "newUsername") String newUsername, @RequestParam(name = "newUsername") String newUsername,
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
RedirectAttributes redirectAttributes) { RedirectAttributes redirectAttributes) {
if (!userService.isUsernameValid(newUsername)) { if (!userService.isUsernameValid(newUsername)) {
return new RedirectView("/account?messageType=invalidUsername"); return new RedirectView("/account?messageType=invalidUsername", true);
} }
if (principal == null) { if (principal == null) {
return new RedirectView("/account?messageType=notAuthenticated"); return new RedirectView("/account?messageType=notAuthenticated", true);
} }
// The username MUST be unique when renaming // The username MUST be unique when renaming
Optional<User> userOpt = userService.findByUsername(principal.getName()); Optional<User> userOpt = userService.findByUsername(principal.getName());
if (userOpt == null || userOpt.isEmpty()) { if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/account?messageType=userNotFound"); return new RedirectView("/account?messageType=userNotFound", true);
} }
User user = userOpt.get(); User user = userOpt.get();
if (user.getUsername().equals(newUsername)) { if (user.getUsername().equals(newUsername)) {
return new RedirectView("/account?messageType=usernameExists"); return new RedirectView("/account?messageType=usernameExists", true);
} }
if (!userService.isPasswordCorrect(user, currentPassword)) { if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/account?messageType=incorrectPassword"); return new RedirectView("/account?messageType=incorrectPassword", true);
} }
if (!user.getUsername().equals(newUsername) && userService.usernameExists(newUsername)) { if (!user.getUsername().equals(newUsername) && userService.usernameExists(newUsername)) {
return new RedirectView("/account?messageType=usernameExists"); return new RedirectView("/account?messageType=usernameExists", true);
} }
if (newUsername != null && newUsername.length() > 0) { if (newUsername != null && newUsername.length() > 0) {
try { try {
userService.changeUsername(user, newUsername); userService.changeUsername(user, newUsername);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new RedirectView("/account?messageType=invalidUsername"); return new RedirectView("/account?messageType=invalidUsername", true);
} }
} }
// Logout using Spring's utility // Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null); new SecurityContextLogoutHandler().logout(request, response, null);
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED); return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED, true);
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@@ -118,19 +118,19 @@ public class UserController {
HttpServletResponse response, HttpServletResponse response,
RedirectAttributes redirectAttributes) { RedirectAttributes redirectAttributes) {
if (principal == null) { if (principal == null) {
return new RedirectView("/change-creds?messageType=notAuthenticated"); return new RedirectView("/change-creds?messageType=notAuthenticated", true);
} }
Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName()); Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName());
if (userOpt == null || userOpt.isEmpty()) { if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/change-creds?messageType=userNotFound"); return new RedirectView("/change-creds?messageType=userNotFound", true);
} }
User user = userOpt.get(); User user = userOpt.get();
if (!userService.isPasswordCorrect(user, currentPassword)) { if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/change-creds?messageType=incorrectPassword"); return new RedirectView("/change-creds?messageType=incorrectPassword", true);
} }
userService.changePassword(user, newPassword); userService.changePassword(user, newPassword);
@@ -138,7 +138,7 @@ public class UserController {
// Logout using Spring's utility // Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null); new SecurityContextLogoutHandler().logout(request, response, null);
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED); return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED, true);
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@@ -151,19 +151,19 @@ public class UserController {
HttpServletResponse response, HttpServletResponse response,
RedirectAttributes redirectAttributes) { RedirectAttributes redirectAttributes) {
if (principal == null) { if (principal == null) {
return new RedirectView("/account?messageType=notAuthenticated"); return new RedirectView("/account?messageType=notAuthenticated", true);
} }
Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName()); Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName());
if (userOpt == null || userOpt.isEmpty()) { if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/account?messageType=userNotFound"); return new RedirectView("/account?messageType=userNotFound", true);
} }
User user = userOpt.get(); User user = userOpt.get();
if (!userService.isPasswordCorrect(user, currentPassword)) { if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/account?messageType=incorrectPassword"); return new RedirectView("/account?messageType=incorrectPassword", true);
} }
userService.changePassword(user, newPassword); userService.changePassword(user, newPassword);
@@ -171,7 +171,7 @@ public class UserController {
// Logout using Spring's utility // Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null); new SecurityContextLogoutHandler().logout(request, response, null);
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED); return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED, true);
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@@ -204,7 +204,7 @@ public class UserController {
boolean forceChange) { boolean forceChange) {
if (!userService.isUsernameValid(username)) { if (!userService.isUsernameValid(username)) {
return new RedirectView("/addUsers?messageType=invalidUsername"); return new RedirectView("/addUsers?messageType=invalidUsername", true);
} }
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username); Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
@@ -212,26 +212,27 @@ public class UserController {
if (userOpt.isPresent()) { if (userOpt.isPresent()) {
User user = userOpt.get(); User user = userOpt.get();
if (user != null && user.getUsername().equalsIgnoreCase(username)) { if (user != null && user.getUsername().equalsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=usernameExists"); return new RedirectView("/addUsers?messageType=usernameExists", true);
} }
} }
if (userService.usernameExistsIgnoreCase(username)) { if (userService.usernameExistsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=usernameExists"); return new RedirectView("/addUsers?messageType=usernameExists", true);
} }
try { try {
// Validate the role // Validate the role
Role roleEnum = Role.fromString(role); Role roleEnum = Role.fromString(role);
if (roleEnum == Role.INTERNAL_API_USER) { if (roleEnum == Role.INTERNAL_API_USER) {
// If the role is INTERNAL_API_USER, reject the request // If the role is INTERNAL_API_USER, reject the request
return new RedirectView("/addUsers?messageType=invalidRole"); return new RedirectView("/addUsers?messageType=invalidRole", true);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// If the role ID is not valid, redirect with an error message // If the role ID is not valid, redirect with an error message
return new RedirectView("/addUsers?messageType=invalidRole"); return new RedirectView("/addUsers?messageType=invalidRole", true);
} }
userService.saveUser(username, password, role, forceChange); userService.saveUser(username, password, role, forceChange);
return new RedirectView("/addUsers"); // Redirect to account page after adding the user return new RedirectView(
"/addUsers", true); // Redirect to account page after adding the user
} }
@PreAuthorize("hasRole('ROLE_ADMIN')") @PreAuthorize("hasRole('ROLE_ADMIN')")
@@ -244,33 +245,34 @@ public class UserController {
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username); Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
if (!userOpt.isPresent()) { if (!userOpt.isPresent()) {
return new RedirectView("/addUsers?messageType=userNotFound"); return new RedirectView("/addUsers?messageType=userNotFound", true);
} }
if (!userService.usernameExistsIgnoreCase(username)) { if (!userService.usernameExistsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=userNotFound"); return new RedirectView("/addUsers?messageType=userNotFound", true);
} }
// Get the currently authenticated username // Get the currently authenticated username
String currentUsername = authentication.getName(); String currentUsername = authentication.getName();
// Check if the provided username matches the current session's username // Check if the provided username matches the current session's username
if (currentUsername.equalsIgnoreCase(username)) { if (currentUsername.equalsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=downgradeCurrentUser"); return new RedirectView("/addUsers?messageType=downgradeCurrentUser", true);
} }
try { try {
// Validate the role // Validate the role
Role roleEnum = Role.fromString(role); Role roleEnum = Role.fromString(role);
if (roleEnum == Role.INTERNAL_API_USER) { if (roleEnum == Role.INTERNAL_API_USER) {
// If the role is INTERNAL_API_USER, reject the request // If the role is INTERNAL_API_USER, reject the request
return new RedirectView("/addUsers?messageType=invalidRole"); return new RedirectView("/addUsers?messageType=invalidRole", true);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// If the role ID is not valid, redirect with an error message // If the role ID is not valid, redirect with an error message
return new RedirectView("/addUsers?messageType=invalidRole"); return new RedirectView("/addUsers?messageType=invalidRole", true);
} }
User user = userOpt.get(); User user = userOpt.get();
userService.changeRole(user, role); userService.changeRole(user, role);
return new RedirectView("/addUsers"); // Redirect to account page after adding the user return new RedirectView(
"/addUsers", true); // Redirect to account page after adding the user
} }
@PreAuthorize("hasRole('ROLE_ADMIN')") @PreAuthorize("hasRole('ROLE_ADMIN')")
@@ -279,7 +281,7 @@ public class UserController {
@PathVariable(name = "username") String username, Authentication authentication) { @PathVariable(name = "username") String username, Authentication authentication) {
if (!userService.usernameExistsIgnoreCase(username)) { if (!userService.usernameExistsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=deleteUsernameExists"); return new RedirectView("/addUsers?messageType=deleteUsernameExists", true);
} }
// Get the currently authenticated username // Get the currently authenticated username
@@ -287,11 +289,11 @@ public class UserController {
// Check if the provided username matches the current session's username // Check if the provided username matches the current session's username
if (currentUsername.equalsIgnoreCase(username)) { if (currentUsername.equalsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=deleteCurrentUser"); return new RedirectView("/addUsers?messageType=deleteCurrentUser", true);
} }
invalidateUserSessions(username); invalidateUserSessions(username);
userService.deleteUser(username); userService.deleteUser(username);
return new RedirectView("/addUsers"); return new RedirectView("/addUsers", true);
} }
@Autowired private SessionRegistry sessionRegistry; @Autowired private SessionRegistry sessionRegistry;

View File

@@ -1,10 +1,22 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -26,6 +38,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Convert", description = "Convert APIs") @Tag(name = "Convert", description = "Convert APIs")
public class ConvertPDFToPDFA { public class ConvertPDFToPDFA {
private static final Logger logger = LoggerFactory.getLogger(ConvertPDFToPDFA.class);
@PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa") @PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@Operation( @Operation(
summary = "Convert a PDF to a PDF/A", summary = "Convert a PDF to a PDF/A",
@@ -36,9 +50,39 @@ public class ConvertPDFToPDFA {
MultipartFile inputFile = request.getFileInput(); MultipartFile inputFile = request.getFileInput();
String outputFormat = request.getOutputFormat(); String outputFormat = request.getOutputFormat();
// Save the uploaded file to a temporary location // Convert MultipartFile to byte[]
byte[] pdfBytes = inputFile.getBytes();
// Load the PDF document
PDDocument document = Loader.loadPDF(pdfBytes);
// Get the document catalog
PDDocumentCatalog catalog = document.getDocumentCatalog();
// Get the AcroForm
PDAcroForm acroForm = catalog.getAcroForm();
if (acroForm != null) {
// Remove signature fields safely
List<PDField> fieldsToRemove =
acroForm.getFields().stream()
.filter(field -> field instanceof PDSignatureField)
.collect(Collectors.toList());
if (!fieldsToRemove.isEmpty()) {
acroForm.flatten(fieldsToRemove, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.save(baos);
pdfBytes = baos.toByteArray();
}
}
document.close();
// Save the uploaded (and possibly modified) file to a temporary location
Path tempInputFile = Files.createTempFile("input_", ".pdf"); Path tempInputFile = Files.createTempFile("input_", ".pdf");
inputFile.transferTo(tempInputFile.toFile()); try (OutputStream outputStream = new FileOutputStream(tempInputFile.toFile())) {
outputStream.write(pdfBytes);
}
// Prepare the output file path // Prepare the output file path
Path tempOutputFile = Files.createTempFile("output_", ".pdf"); Path tempOutputFile = Files.createTempFile("output_", ".pdf");
@@ -58,7 +102,7 @@ public class ConvertPDFToPDFA {
.runCommandWithOutputHandling(command); .runCommandWithOutputHandling(command);
// Read the optimized PDF file // Read the optimized PDF file
byte[] pdfBytes = Files.readAllBytes(tempOutputFile); byte[] optimizedPdfBytes = Files.readAllBytes(tempOutputFile);
// Clean up the temporary files // Clean up the temporary files
Files.deleteIfExists(tempInputFile); Files.deleteIfExists(tempInputFile);
@@ -69,6 +113,6 @@ public class ConvertPDFToPDFA {
Filenames.toSimpleFileName(inputFile.getOriginalFilename()) Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "") .replaceFirst("[.][^.]+$", "")
+ "_PDFA.pdf"; + "_PDFA.pdf";
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename); return WebResponseUtils.bytesToWebResponse(optimizedPdfBytes, outputFilename);
} }
} }

View File

@@ -15,6 +15,8 @@ import java.util.zip.ZipOutputStream;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@@ -43,6 +45,7 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
public class AutoSplitPdfController { public class AutoSplitPdfController {
private static final Logger logger = LoggerFactory.getLogger(AutoSplitPdfController.class);
private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF"; private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF";
private static final String QR_CONTENT_OLD = "https://github.com/Frooodle/Stirling-PDF"; private static final String QR_CONTENT_OLD = "https://github.com/Frooodle/Stirling-PDF";
@@ -115,7 +118,7 @@ public class AutoSplitPdfController {
zipOut.closeEntry(); zipOut.closeEntry();
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("exception", e);
} finally { } finally {
data = Files.readAllBytes(zipFile); data = Files.readAllBytes(zipFile);
Files.deleteIfExists(zipFile); Files.deleteIfExists(zipFile);

View File

@@ -106,7 +106,7 @@ public class BlankPageController {
.replaceFirst("[.][^.]+$", "") .replaceFirst("[.][^.]+$", "")
+ "_blanksRemoved.pdf"); + "_blanksRemoved.pdf");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} finally { } finally {
if (document != null) document.close(); if (document != null) document.close();

View File

@@ -110,8 +110,8 @@ public class FakeScanControllerWIP {
private BufferedImage rotate(BufferedImage image, double rotation) { private BufferedImage rotate(BufferedImage image, double rotation) {
double rotationRequired = Math.toRadians(rotation); double rotationRequired = Math.toRadians(rotation);
double locationX = image.getWidth() / 2; double locationX = (double) image.getWidth() / 2;
double locationY = image.getHeight() / 2; double locationY = (double) image.getHeight() / 2;
AffineTransform tx = AffineTransform tx =
AffineTransform.getRotateInstance(rotationRequired, locationX, locationY); AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC); AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC);
@@ -127,8 +127,8 @@ public class FakeScanControllerWIP {
for (int i = -radius; i <= radius; i++) { for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) { for (int j = -radius; j <= radius; j++) {
double xDistance = i * i; double xDistance = (double) i * i;
double yDistance = j * j; double yDistance = (double) j * j;
double g = Math.exp(-(xDistance + yDistance) / (2 * sigma * sigma)); double g = Math.exp(-(xDistance + yDistance) / (2 * sigma * sigma));
data[(i + radius) * size + j + radius] = (float) g; data[(i + radius) * size + j + radius] = (float) g;
sum += g; sum += g;
@@ -137,7 +137,7 @@ public class FakeScanControllerWIP {
// Normalize the kernel // Normalize the kernel
for (int i = 0; i < data.length; i++) { for (int i = 0; i < data.length; i++) {
data[i] /= sum; if (sum != 0) data[i] /= sum;
} }
Kernel kernel = new Kernel(size, size, data); Kernel kernel = new Kernel(size, size, data);
@@ -166,7 +166,7 @@ public class FakeScanControllerWIP {
0, 0,
new Color(0, 0, 0, 1f), new Color(0, 0, 0, 1f),
0, 0,
featherRadius * 2, featherRadius * 2f,
new Color(0, 0, 0, 0f))); new Color(0, 0, 0, 0f)));
g2.fillRect(0, 0, width, featherRadius); g2.fillRect(0, 0, width, featherRadius);
@@ -174,7 +174,7 @@ public class FakeScanControllerWIP {
g2.setPaint( g2.setPaint(
new GradientPaint( new GradientPaint(
0, 0,
height - featherRadius * 2, height - featherRadius * 2f,
new Color(0, 0, 0, 0f), new Color(0, 0, 0, 0f),
0, 0,
height, height,
@@ -187,7 +187,7 @@ public class FakeScanControllerWIP {
0, 0,
0, 0,
new Color(0, 0, 0, 1f), new Color(0, 0, 0, 1f),
featherRadius * 2, featherRadius * 2f,
0, 0,
new Color(0, 0, 0, 0f))); new Color(0, 0, 0, 0f)));
g2.fillRect(0, 0, featherRadius, height); g2.fillRect(0, 0, featherRadius, height);
@@ -195,7 +195,7 @@ public class FakeScanControllerWIP {
// Right edge // Right edge
g2.setPaint( g2.setPaint(
new GradientPaint( new GradientPaint(
width - featherRadius * 2, width - featherRadius * 2f,
0, 0,
new Color(0, 0, 0, 0f), new Color(0, 0, 0, 0f),
width, width,
@@ -244,7 +244,7 @@ public class FakeScanControllerWIP {
int y2 = y1 + random.nextInt(20) - 10; int y2 = y1 + random.nextInt(20) - 10;
Path2D.Double hair = new Path2D.Double(); Path2D.Double hair = new Path2D.Double();
hair.moveTo(x1, y1); hair.moveTo(x1, y1);
hair.curveTo(x1, y1, (x1 + x2) / 2, (y1 + y2) / 2, x2, y2); hair.curveTo(x1, y1, (double) (x1 + x2) / 2, (double) (y1 + y2) / 2, x2, y2);
g2d.draw(hair); g2d.draw(hair);
} }

View File

@@ -12,6 +12,8 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -33,6 +35,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
public class FlattenController { public class FlattenController {
private static final Logger logger = LoggerFactory.getLogger(FlattenController.class);
@PostMapping(consumes = "multipart/form-data", value = "/flatten") @PostMapping(consumes = "multipart/form-data", value = "/flatten")
@Operation( @Operation(
summary = "Flatten PDF form fields or full page", summary = "Flatten PDF form fields or full page",
@@ -73,7 +77,7 @@ public class FlattenController {
contentStream.drawImage(pdImage, 0, 0, pageWidth, pageHeight); contentStream.drawImage(pdImage, 0, 0, pageWidth, pageHeight);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
} }
PdfUtils.setMetadataToPdf(newDocument, metadata); PdfUtils.setMetadataToPdf(newDocument, metadata);

View File

@@ -11,6 +11,8 @@ import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -30,6 +32,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
public class MetadataController { public class MetadataController {
private static final Logger logger = LoggerFactory.getLogger(MetadataController.class);
private String checkUndefined(String entry) { private String checkUndefined(String entry) {
// Check if the string is "undefined" // Check if the string is "undefined"
if ("undefined".equals(entry)) { if ("undefined".equals(entry)) {
@@ -136,7 +140,7 @@ public class MetadataController {
creationDateCal.setTime( creationDateCal.setTime(
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(creationDate)); new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(creationDate));
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); logger.error("exception", e);
} }
info.setCreationDate(creationDateCal); info.setCreationDate(creationDateCal);
} else { } else {
@@ -148,7 +152,7 @@ public class MetadataController {
modificationDateCal.setTime( modificationDateCal.setTime(
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(modificationDate)); new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(modificationDate));
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); logger.error("exception", e);
} }
info.setModificationDate(modificationDateCal); info.setModificationDate(modificationDateCal);
} else { } else {

View File

@@ -19,6 +19,7 @@ import java.util.stream.Stream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@@ -28,6 +29,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import stirling.software.SPDF.model.PipelineConfig; import stirling.software.SPDF.model.PipelineConfig;
import stirling.software.SPDF.model.PipelineOperation; import stirling.software.SPDF.model.PipelineOperation;
import stirling.software.SPDF.utils.FileMonitor;
@Service @Service
public class PipelineDirectoryProcessor { public class PipelineDirectoryProcessor {
@@ -35,11 +37,18 @@ public class PipelineDirectoryProcessor {
private static final Logger logger = LoggerFactory.getLogger(PipelineDirectoryProcessor.class); private static final Logger logger = LoggerFactory.getLogger(PipelineDirectoryProcessor.class);
@Autowired private ObjectMapper objectMapper; @Autowired private ObjectMapper objectMapper;
@Autowired private ApiDocService apiDocService; @Autowired private ApiDocService apiDocService;
final String watchedFoldersDir = "./pipeline/watchedFolders/";
final String finishedFoldersDir = "./pipeline/finishedFolders/";
@Autowired PipelineProcessor processor; @Autowired PipelineProcessor processor;
@Autowired FileMonitor fileMonitor;
final String watchedFoldersDir;
final String finishedFoldersDir;
public PipelineDirectoryProcessor(
@Qualifier("watchedFoldersDir") String watchedFoldersDir,
@Qualifier("finishedFoldersDir") String finishedFoldersDir) {
this.watchedFoldersDir = watchedFoldersDir;
this.finishedFoldersDir = finishedFoldersDir;
}
@Scheduled(fixedRate = 60000) @Scheduled(fixedRate = 60000)
public void scanFolders() { public void scanFolders() {
@@ -130,7 +139,11 @@ public class PipelineDirectoryProcessor {
throws IOException { throws IOException {
try (Stream<Path> paths = Files.list(dir)) { try (Stream<Path> paths = Files.list(dir)) {
if ("automated".equals(operation.getParameters().get("fileInput"))) { if ("automated".equals(operation.getParameters().get("fileInput"))) {
return paths.filter(path -> !Files.isDirectory(path) && !path.equals(jsonFile)) return paths.filter(
path ->
!Files.isDirectory(path)
&& !path.equals(jsonFile)
&& fileMonitor.isFileReadyForProcessing(path))
.map(Path::toFile) .map(Path::toFile)
.toArray(File[]::new); .toArray(File[]::new);
} else { } else {

View File

@@ -105,7 +105,14 @@ public class PipelineProcessor {
body.add("fileInput", file); body.add("fileInput", file);
for (Entry<String, Object> entry : parameters.entrySet()) { for (Entry<String, Object> entry : parameters.entrySet()) {
body.add(entry.getKey(), entry.getValue()); if (entry.getValue() instanceof List) {
List<?> list = (List<?>) entry.getValue();
for (Object item : list) {
body.add(entry.getKey(), item);
}
} else {
body.add(entry.getKey(), entry.getValue());
}
} }
ResponseEntity<byte[]> response = sendWebRequest(url, body); ResponseEntity<byte[]> response = sendWebRequest(url, body);
@@ -167,7 +174,14 @@ public class PipelineProcessor {
} }
for (Entry<String, Object> entry : parameters.entrySet()) { for (Entry<String, Object> entry : parameters.entrySet()) {
body.add(entry.getKey(), entry.getValue()); if (entry.getValue() instanceof List) {
List<?> list = (List<?>) entry.getValue();
for (Object item : list) {
body.add(entry.getKey(), item);
}
} else {
body.add(entry.getKey(), entry.getValue());
}
} }
ResponseEntity<byte[]> response = sendWebRequest(url, body); ResponseEntity<byte[]> response = sendWebRequest(url, body);

View File

@@ -148,7 +148,7 @@ public class CertSignController {
doc.addSignature(signature, instance); doc.addSignature(signature, instance);
doc.saveIncremental(output); doc.saveIncremental(output);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("exception", e);
} }
} }

View File

@@ -56,6 +56,8 @@ import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.xml.DomXmpParser; import org.apache.xmpbox.xml.DomXmpParser;
import org.apache.xmpbox.xml.XmpParsingException; import org.apache.xmpbox.xml.XmpParsingException;
import org.apache.xmpbox.xml.XmpSerializer; import org.apache.xmpbox.xml.XmpSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@@ -79,6 +81,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@Tag(name = "Security", description = "Security APIs") @Tag(name = "Security", description = "Security APIs")
public class GetInfoOnPDF { public class GetInfoOnPDF {
private static final Logger logger = LoggerFactory.getLogger(GetInfoOnPDF.class);
static ObjectMapper objectMapper = new ObjectMapper(); static ObjectMapper objectMapper = new ObjectMapper();
@PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf") @PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
@@ -220,7 +224,7 @@ public class GetInfoOnPDF {
javascriptArray.add(jsNode); javascriptArray.add(jsNode);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
} }
} }
@@ -253,7 +257,7 @@ public class GetInfoOnPDF {
} }
} catch (Exception e) { } catch (Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); logger.error("exception", e);
} }
boolean isPdfACompliant = checkForStandard(pdfBoxDoc, "PDF/A"); boolean isPdfACompliant = checkForStandard(pdfBoxDoc, "PDF/A");
@@ -305,7 +309,7 @@ public class GetInfoOnPDF {
new XmpSerializer().serialize(xmpMeta, os, true); new XmpSerializer().serialize(xmpMeta, os, true);
xmpString = new String(os.toByteArray(), StandardCharsets.UTF_8); xmpString = new String(os.toByteArray(), StandardCharsets.UTF_8);
} catch (XmpParsingException | IOException e) { } catch (XmpParsingException | IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
} }
@@ -593,7 +597,7 @@ public class GetInfoOnPDF {
MediaType.APPLICATION_JSON); MediaType.APPLICATION_JSON);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("exception", e);
} }
return null; return null;
} }
@@ -691,7 +695,7 @@ public class GetInfoOnPDF {
Exception Exception
e) { // Catching general exception for brevity, ideally you'd catch specific e) { // Catching general exception for brevity, ideally you'd catch specific
// exceptions. // exceptions.
e.printStackTrace(); logger.error("exception", e);
} }
return false; return false;

View File

@@ -0,0 +1,81 @@
package stirling.software.SPDF.controller.api.security;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.SPDF.utils.WebResponseUtils;
@RestController
@RequestMapping("/api/v1/security")
@Tag(name = "Security", description = "Security APIs")
public class RemoveCertSignController {
private static final Logger logger = LoggerFactory.getLogger(RemoveCertSignController.class);
@PostMapping(consumes = "multipart/form-data", value = "/remove-cert-sign")
@Operation(
summary = "Remove digital signature from PDF",
description =
"This endpoint accepts a PDF file and returns the PDF file without the digital signature. Input: PDF, Output: PDF")
public ResponseEntity<byte[]> removeCertSignPDF(@ModelAttribute PDFFile request)
throws Exception {
MultipartFile pdf = request.getFileInput();
// Convert MultipartFile to byte[]
byte[] pdfBytes = pdf.getBytes();
// Create a ByteArrayOutputStream to hold the resulting PDF
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Load the PDF document
PDDocument document = Loader.loadPDF(pdfBytes);
// Get the document catalog
PDDocumentCatalog catalog = document.getDocumentCatalog();
// Get the AcroForm
PDAcroForm acroForm = catalog.getAcroForm();
if (acroForm != null) {
// Remove signature fields safely
List<PDField> fieldsToRemove =
acroForm.getFields().stream()
.filter(field -> field instanceof PDSignatureField)
.collect(Collectors.toList());
if (!fieldsToRemove.isEmpty()) {
acroForm.flatten(fieldsToRemove, false);
}
}
// Save the modified document to the ByteArrayOutputStream
document.save(baos);
document.close();
// Return the modified PDF as a response
return WebResponseUtils.boasToWebResponse(
baos,
Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
+ "_unsigned.pdf");
}
}

View File

@@ -117,7 +117,6 @@ public class PDFTableStripper extends PDFTextStripper {
/** /**
* Instantiate a new PDFTableStripper object. * Instantiate a new PDFTableStripper object.
* *
* @param document
* @throws IOException If there is an error loading the properties. * @throws IOException If there is an error loading the properties.
*/ */
public PDFTableStripper() throws IOException { public PDFTableStripper() throws IOException {

View File

@@ -52,23 +52,23 @@ public class AccountWebController {
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
if (oauth != null) { if (oauth != null) {
if (oauth.isSettingsValid()) { if (oauth.isSettingsValid()) {
providerList.put("oidc", "OpenID Connect"); providerList.put("oidc", oauth.getProvider());
} }
Client client = oauth.getClient(); Client client = oauth.getClient();
if (client != null) { if (client != null) {
GoogleProvider google = client.getGoogle(); GoogleProvider google = client.getGoogle();
if (google.isSettingsValid()) { if (google.isSettingsValid()) {
providerList.put("google", "Google"); providerList.put(google.getName(), google.getClientName());
} }
GithubProvider github = client.getGithub(); GithubProvider github = client.getGithub();
if (github.isSettingsValid()) { if (github.isSettingsValid()) {
providerList.put("github", "Github"); providerList.put(github.getName(), github.getClientName());
} }
KeycloakProvider keycloak = client.getKeycloak(); KeycloakProvider keycloak = client.getKeycloak();
if (keycloak.isSettingsValid()) { if (keycloak.isSettingsValid()) {
providerList.put("keycloak", "Keycloak"); providerList.put(keycloak.getName(), keycloak.getClientName());
} }
} }
} }
@@ -262,8 +262,7 @@ public class AccountWebController {
userRepository.findByUsernameIgnoreCase( userRepository.findByUsernameIgnoreCase(
username); // Assuming findByUsername method exists username); // Assuming findByUsername method exists
if (!user.isPresent()) { if (!user.isPresent()) {
// Handle error appropriately return "redirect:/error";
return "redirect:/error"; // Example redirection in case of error
} }
// Convert settings map to JSON string // Convert settings map to JSON string
@@ -273,8 +272,8 @@ public class AccountWebController {
settingsJson = objectMapper.writeValueAsString(user.get().getSettings()); settingsJson = objectMapper.writeValueAsString(user.get().getSettings());
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
// Handle JSON conversion error // Handle JSON conversion error
e.printStackTrace(); logger.error("exception", e);
return "redirect:/error"; // Example redirection in case of error return "redirect:/error";
} }
String messageType = request.getParameter("messageType"); String messageType = request.getParameter("messageType");

View File

@@ -15,6 +15,8 @@ import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
@@ -33,6 +35,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
@Tag(name = "General", description = "General APIs") @Tag(name = "General", description = "General APIs")
public class GeneralWebController { public class GeneralWebController {
private static final Logger logger = LoggerFactory.getLogger(GeneralWebController.class);
@GetMapping("/pipeline") @GetMapping("/pipeline")
@Hidden @Hidden
public String pipelineForm(Model model) { public String pipelineForm(Model model) {
@@ -74,7 +78,7 @@ public class GeneralWebController {
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
} }
if (pipelineConfigsWithNames.size() == 0) { if (pipelineConfigsWithNames.size() == 0) {

View File

@@ -6,6 +6,8 @@ import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@@ -26,6 +28,8 @@ import stirling.software.SPDF.model.Dependency;
@Controller @Controller
public class HomeWebController { public class HomeWebController {
private static final Logger logger = LoggerFactory.getLogger(HomeWebController.class);
@GetMapping("/about") @GetMapping("/about")
@Hidden @Hidden
public String gameForm(Model model) { public String gameForm(Model model) {
@@ -46,7 +50,7 @@ public class HomeWebController {
mapper.readValue(json, new TypeReference<Map<String, List<Dependency>>>() {}); mapper.readValue(json, new TypeReference<Map<String, List<Dependency>>>() {});
model.addAttribute("dependencies", data.get("dependencies")); model.addAttribute("dependencies", data.get("dependencies"));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
return "licenses"; return "licenses";
} }

View File

@@ -53,6 +53,13 @@ public class SecurityWebController {
return "security/cert-sign"; return "security/cert-sign";
} }
@GetMapping("/remove-cert-sign")
@Hidden
public String certUnSignForm(Model model) {
model.addAttribute("currentPage", "remove-cert-sign");
return "security/remove-cert-sign";
}
@GetMapping("/sanitize-pdf") @GetMapping("/sanitize-pdf")
@Hidden @Hidden
public String sanitizeForm(Model model) { public String sanitizeForm(Model model) {

View File

@@ -356,8 +356,8 @@ public class ApplicationProperties {
private KeycloakProvider keycloak = new KeycloakProvider(); private KeycloakProvider keycloak = new KeycloakProvider();
public Provider get(String registrationId) throws Exception { public Provider get(String registrationId) throws Exception {
switch (registrationId) { switch (registrationId.toLowerCase()) {
case "gogole": case "google":
return getGoogle(); return getGoogle();
case "github": case "github":
return getGithub(); return getGithub();
@@ -455,6 +455,7 @@ public class ApplicationProperties {
@Override @Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("https://www.googleapis.com/auth/userinfo.email"); scopes.add("https://www.googleapis.com/auth/userinfo.email");
scopes.add("https://www.googleapis.com/auth/userinfo.profile"); scopes.add("https://www.googleapis.com/auth/userinfo.profile");
} }
@@ -495,6 +496,11 @@ public class ApplicationProperties {
return "google"; return "google";
} }
@Override
public String getClientName() {
return "Google";
}
public boolean isSettingsValid() { public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId") return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret") && super.isValid(this.getClientSecret(), "clientSecret")
@@ -553,8 +559,10 @@ public class ApplicationProperties {
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
} }
@Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("read:user"); scopes.add("read:user");
} }
return scopes; return scopes;
@@ -594,6 +602,11 @@ public class ApplicationProperties {
return "github"; return "github";
} }
@Override
public String getClientName() {
return "GitHub";
}
public boolean isSettingsValid() { public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId") return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret") && super.isValid(this.getClientSecret(), "clientSecret")
@@ -642,13 +655,14 @@ public class ApplicationProperties {
@Override @Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes.add("openid"); scopes = new ArrayList<>();
scopes.add("profile"); scopes.add("profile");
scopes.add("email"); scopes.add("email");
} }
return scopes; return scopes;
} }
@Override
public void setScopes(String scopes) { public void setScopes(String scopes) {
this.scopes = this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList()); Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
@@ -684,6 +698,11 @@ public class ApplicationProperties {
return "keycloak"; return "keycloak";
} }
@Override
public String getClientName() {
return "Keycloak";
}
public boolean isSettingsValid() { public boolean isSettingsValid() {
return isValid(this.getIssuer(), "issuer") return isValid(this.getIssuer(), "issuer")
&& isValid(this.getClientId(), "clientId") && isValid(this.getClientId(), "clientId")

View File

@@ -0,0 +1,45 @@
package stirling.software.SPDF.model;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import org.thymeleaf.templateresource.ITemplateResource;
public class InputStreamTemplateResource implements ITemplateResource {
private InputStream inputStream;
private String characterEncoding;
public InputStreamTemplateResource(InputStream inputStream, String characterEncoding) {
this.inputStream = inputStream;
this.characterEncoding = characterEncoding;
}
@Override
public Reader reader() throws IOException {
return new InputStreamReader(inputStream, characterEncoding);
}
@Override
public ITemplateResource relative(String relativeLocation) {
// Implement logic for relative resources, if needed
throw new UnsupportedOperationException("Relative resources not supported");
}
@Override
public String getDescription() {
return "InputStream resource [Stream]";
}
@Override
public String getBaseName() {
return "streamResource";
}
@Override
public boolean exists() {
// TODO Auto-generated method stub
return false;
}
}

View File

@@ -4,11 +4,16 @@ import java.util.Collection;
public class Provider implements ProviderInterface { public class Provider implements ProviderInterface {
private String name; private String name;
private String clientName;
public String getName() { public String getName() {
return name; return name;
} }
public String getClientName() {
return clientName;
}
protected boolean isValid(String value, String name) { protected boolean isValid(String value, String name) {
if (value != null && !value.trim().isEmpty()) { if (value != null && !value.trim().isEmpty()) {
return true; return true;

View File

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

View File

@@ -5,6 +5,8 @@ import java.util.List;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@@ -19,6 +21,8 @@ import stirling.software.SPDF.utils.GeneralUtils;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PDFWithPageNums extends PDFFile { public class PDFWithPageNums extends PDFFile {
private static final Logger logger = LoggerFactory.getLogger(PDFWithPageNums.class);
@Schema( @Schema(
description = description =
"The pages to select, Supports ranges (e.g., '1,3,5-9'), or 'all' 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')\"") "The pages to select, Supports ranges (e.g., '1,3,5-9'), or 'all' 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')\"")
@@ -31,7 +35,7 @@ public class PDFWithPageNums extends PDFFile {
pageCount = Loader.loadPDF(getFileInput().getBytes()).getNumberOfPages(); pageCount = Loader.loadPDF(getFileInput().getBytes()).getNumberOfPages();
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); logger.error("exception", e);
} }
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount); return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
} }

View File

@@ -21,4 +21,10 @@ public class MergePdfsRequest extends MultiplePDFFiles {
}, },
defaultValue = "orderProvided") defaultValue = "orderProvided")
private String sortType = "orderProvided"; private String sortType = "orderProvided";
@Schema(
description =
"Flag indicating whether to remove certification signatures from the merged PDF. If true, all certification signatures will be removed from the final merged document.",
example = "true")
private boolean isRemoveCertSign;
} }

View File

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

View File

@@ -0,0 +1,168 @@
package stirling.software.SPDF.utils;
import static java.nio.file.StandardWatchEventKinds.*;
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class FileMonitor {
private static final Logger logger = LoggerFactory.getLogger(FileMonitor.class);
private final Map<Path, WatchKey> path2KeyMapping;
private final Set<Path> newlyDiscoveredFiles;
private final ConcurrentHashMap.KeySetView<Path, Boolean> readyForProcessingFiles;
private final WatchService watchService;
private final Predicate<Path> pathFilter;
private final Path rootDir;
private Set<Path> stagingFiles;
/**
* @param rootDirectory the root directory to monitor
* @param pathFilter the filter to apply to the paths, return true if the path should be
* monitored, false otherwise
*/
@Autowired
public FileMonitor(
@Qualifier("watchedFoldersDir") String rootDirectory,
@Qualifier("directoryFilter") Predicate<Path> pathFilter)
throws IOException {
this.newlyDiscoveredFiles = new HashSet<>();
this.path2KeyMapping = new HashMap<>();
this.stagingFiles = new HashSet<>();
this.pathFilter = pathFilter;
this.readyForProcessingFiles = ConcurrentHashMap.newKeySet();
this.watchService = FileSystems.getDefault().newWatchService();
this.rootDir = Path.of(rootDirectory);
}
private boolean shouldNotProcess(Path path) {
return !pathFilter.test(path);
}
private void recursivelyRegisterEntry(Path dir) throws IOException {
WatchKey key = dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
path2KeyMapping.put(dir, key);
logger.info("Registered directory: {}", dir);
try (Stream<Path> directoryVisitor = Files.walk(dir, 1)) {
final Iterator<Path> iterator = directoryVisitor.iterator();
while (iterator.hasNext()) {
Path path = iterator.next();
if (path.equals(dir) || shouldNotProcess(path)) continue;
if (Files.isDirectory(path)) {
recursivelyRegisterEntry(path);
} else if (Files.isRegularFile(path)) {
handleFileCreation(path);
}
}
}
}
@Scheduled(fixedRate = 5000)
public void trackFiles() {
/*
All files observed changes in the last iteration will be considered as staging files.
If those files are not modified in current iteration, they will be considered as ready for processing.
*/
stagingFiles = new HashSet<>(newlyDiscoveredFiles);
readyForProcessingFiles.clear();
if (path2KeyMapping.isEmpty()) {
logger.warn(
"not monitoring any directory, even the root directory itself: {}", rootDir);
if (Files.exists(
rootDir)) { // if the root directory exists, re-register the root directory
try {
recursivelyRegisterEntry(rootDir);
} catch (IOException e) {
logger.error("unable to register monitoring", e);
}
}
}
WatchKey key;
while ((key = watchService.poll()) != null) {
final Path watchingDir = (Path) key.watchable();
key.pollEvents()
.forEach(
(evt) -> {
final Path path = (Path) evt.context();
final WatchEvent.Kind<?> kind = evt.kind();
if (shouldNotProcess(path)) return;
try {
if (Files.isDirectory(path)) {
if (kind == ENTRY_CREATE) {
handleDirectoryCreation(path);
}
/*
we don't need to handle directory deletion or modification
- directory deletion will be handled by key.reset()
- directory modification indicates a new file creation or deletion, which is handled by below
*/
}
Path relativePathFromRoot = watchingDir.resolve(path);
if (kind == ENTRY_CREATE) {
handleFileCreation(relativePathFromRoot);
} else if (kind == ENTRY_DELETE) {
handleFileRemoval(relativePathFromRoot);
} else if (kind == ENTRY_MODIFY) {
handleFileModification(relativePathFromRoot);
}
} catch (Exception e) {
logger.error("Error while processing file: {}", path, e);
}
});
boolean isKeyValid = key.reset();
if (!isKeyValid) { // key is invalid when the directory itself is no longer exists
path2KeyMapping.remove((Path) key.watchable());
}
}
readyForProcessingFiles.addAll(stagingFiles);
}
private void handleDirectoryCreation(Path dir) throws IOException {
WatchKey key = dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
path2KeyMapping.put(dir, key);
}
private void handleFileRemoval(Path path) {
newlyDiscoveredFiles.remove(path);
stagingFiles.remove(path);
}
private void handleFileCreation(Path path) {
newlyDiscoveredFiles.add(path);
stagingFiles.remove(path);
}
private void handleFileModification(Path path) {
// the logic is the same
handleFileCreation(path);
}
/**
* Check if the file is ready for processing.
*
* <p>A file is ready for processing if it is not being modified for 5000ms.
*
* @param path the path of the file
* @return true if the file is ready for processing, false otherwise
*/
public boolean isFileReadyForProcessing(Path path) {
return readyForProcessingFiles.contains(path);
}
}

View File

@@ -42,6 +42,7 @@ public class FileToPdf {
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
if (!htmlFormatsInstalled) { if (!htmlFormatsInstalled) {
command.add("weasyprint"); command.add("weasyprint");
command.add("-e utf-8");
command.add(tempInputFile.toString()); command.add(tempInputFile.toString());
command.add(tempOutputFile.toString()); command.add(tempOutputFile.toString());
@@ -52,7 +53,7 @@ public class FileToPdf {
command.add("--paper-size"); command.add("--paper-size");
command.add("a4"); command.add("a4");
if (request.getZoom() != 1.0) { if (request != null && request.getZoom() != 1.0) {
// Create a temporary CSS file // Create a temporary CSS file
File tempCssFile = Files.createTempFile("customStyle", ".css").toFile(); File tempCssFile = Files.createTempFile("customStyle", ".css").toFile();
try (FileWriter writer = new FileWriter(tempCssFile)) { try (FileWriter writer = new FileWriter(tempCssFile)) {

View File

@@ -14,6 +14,8 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.fathzer.soft.javaluator.DoubleEvaluator; import com.fathzer.soft.javaluator.DoubleEvaluator;
@@ -23,6 +25,8 @@ import io.github.pixee.security.Urls;
public class GeneralUtils { public class GeneralUtils {
private static final Logger logger = LoggerFactory.getLogger(GeneralUtils.class);
public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException { public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
File tempFile = Files.createTempFile("temp", null).toFile(); File tempFile = Files.createTempFile("temp", null).toFile();
try (FileOutputStream os = new FileOutputStream(tempFile)) { try (FileOutputStream os = new FileOutputStream(tempFile)) {
@@ -234,7 +238,7 @@ public class GeneralUtils {
try { try {
Files.createDirectories(folder); Files.createDirectories(folder);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
return false; return false;
} }
} }

View File

@@ -14,6 +14,8 @@ import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -24,6 +26,7 @@ import io.github.pixee.security.Filenames;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
public class PDFToFile { public class PDFToFile {
private static final Logger logger = LoggerFactory.getLogger(PDFToFile.class);
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile) public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
throws IOException, InterruptedException { throws IOException, InterruptedException {
@@ -67,18 +70,20 @@ public class PDFToFile {
// Return output files in a ZIP archive // Return output files in a ZIP archive
fileName = pdfBaseName + "ToHtml.zip"; fileName = pdfBaseName + "ToHtml.zip";
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream); try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
for (File outputFile : outputFiles) {
for (File outputFile : outputFiles) { ZipEntry entry = new ZipEntry(outputFile.getName());
ZipEntry entry = new ZipEntry(outputFile.getName()); zipOutputStream.putNextEntry(entry);
zipOutputStream.putNextEntry(entry); try (FileInputStream fis = new FileInputStream(outputFile)) {
FileInputStream fis = new FileInputStream(outputFile); IOUtils.copy(fis, zipOutputStream);
IOUtils.copy(fis, zipOutputStream); } catch (IOException e) {
fis.close(); logger.error("Exception writing zip entry", e);
zipOutputStream.closeEntry(); }
zipOutputStream.closeEntry();
}
} catch (IOException e) {
logger.error("Exception writing zip", e);
} }
zipOutputStream.close();
fileBytes = byteArrayOutputStream.toByteArray(); fileBytes = byteArrayOutputStream.toByteArray();
} finally { } finally {
@@ -135,6 +140,8 @@ public class PDFToFile {
new ArrayList<>( new ArrayList<>(
Arrays.asList( Arrays.asList(
"soffice", "soffice",
"--headless",
"--nologo",
"--infilter=" + libreOfficeFilter, "--infilter=" + libreOfficeFilter,
"--convert-to", "--convert-to",
outputFormat, outputFormat,
@@ -160,18 +167,22 @@ public class PDFToFile {
// Return output files in a ZIP archive // Return output files in a ZIP archive
fileName = pdfBaseName + "To" + outputFormat + ".zip"; fileName = pdfBaseName + "To" + outputFormat + ".zip";
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream); try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
for (File outputFile : outputFiles) {
ZipEntry entry = new ZipEntry(outputFile.getName());
zipOutputStream.putNextEntry(entry);
try (FileInputStream fis = new FileInputStream(outputFile)) {
IOUtils.copy(fis, zipOutputStream);
} catch (IOException e) {
logger.error("Exception writing zip entry", e);
}
for (File outputFile : outputFiles) { zipOutputStream.closeEntry();
ZipEntry entry = new ZipEntry(outputFile.getName()); }
zipOutputStream.putNextEntry(entry); } catch (IOException e) {
FileInputStream fis = new FileInputStream(outputFile); logger.error("Exception writing zip", e);
IOUtils.copy(fis, zipOutputStream);
fis.close();
zipOutputStream.closeEntry();
} }
zipOutputStream.close();
fileBytes = byteArrayOutputStream.toByteArray(); fileBytes = byteArrayOutputStream.toByteArray();
} }

View File

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

View File

@@ -125,7 +125,7 @@ public class ProcessExecutor {
logger.warn( logger.warn(
"Error reader thread was interrupted due to timeout."); "Error reader thread was interrupted due to timeout.");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
}); });
@@ -149,7 +149,7 @@ public class ProcessExecutor {
logger.warn( logger.warn(
"Error reader thread was interrupted due to timeout."); "Error reader thread was interrupted due to timeout.");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); logger.error("exception", e);
} }
}); });

View File

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

View File

@@ -4,6 +4,8 @@ import jakarta.servlet.http.HttpServletRequest;
public class UrlUtils { public class UrlUtils {
private UrlUtils() {}
public static String getOrigin(HttpServletRequest request) { public static String getOrigin(HttpServletRequest request) {
String scheme = request.getScheme(); // http or https String scheme = request.getScheme(); // http or https
String serverName = request.getServerName(); // localhost String serverName = request.getServerName(); // localhost

View File

@@ -21,7 +21,7 @@ saveToBrowser=Save to Browser
close=إغلاق close=إغلاق
filesSelected=الملفات المحددة filesSelected=الملفات المحددة
noFavourites=لم تتم إضافة أي مفضلات noFavourites=لم تتم إضافة أي مفضلات
downloadComplete=Download Complete downloadComplete=إكتمل التحميل
bored=الانتظار بالملل؟ bored=الانتظار بالملل؟
alphabet=الأبجدية alphabet=الأبجدية
downloadPdf=تنزيل PDF downloadPdf=تنزيل PDF
@@ -29,47 +29,48 @@ text=نص
font=الخط font=الخط
selectFillter=- حدد - selectFillter=- حدد -
pageNum=رقم الصفحة pageNum=رقم الصفحة
sizes.small=Small sizes.small=صغير
sizes.medium=Medium sizes.medium=وسط
sizes.large=Large sizes.large=كبير
sizes.x-large=X-Large sizes.x-large=كبير جدا
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
delete=Delete delete=حذف
username=Username username=اسم المستخدم
password=Password password=كلمة المرور
welcome=Welcome welcome=مرحبا
property=Property property=Property
black=Black black=أسود
white=White white=أبيض
red=Red red=أحمر
green=Green green=أخضر
blue=Blue blue=أزرق
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any problems! WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by poweredBy=Powered by
yes=Yes yes=نعم
no=No no=لا
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=لا يمكن خفض دور المستخدم الحالي downgradeCurrentUserMessage=لا يمكن خفض دور المستخدم الحالي
downgradeCurrentUserLongMessage=لا يمكن تخفيض دور المستخدم الحالي. وبالتالي، لن يظهر المستخدم الحالي. downgradeCurrentUserLongMessage=لا يمكن تخفيض دور المستخدم الحالي. وبالتالي، لن يظهر المستخدم الحالي.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user. userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user. userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=خطأ
oops=Oops! oops=Oops!
help=Help help=مساعدة
goHomepage=Go to Homepage goHomepage=الى الصفحة الرئيسية
joinDiscord=Join our Discord server joinDiscord=Join our Discord server
seeDockerHub=See Docker Hub seeDockerHub=See Docker Hub
visitGithub=Visit Github Repository visitGithub=Visit Github Repository
donate=Donate donate=Donate
color=Color color=لون
sponsor=Sponsor sponsor=Sponsor
info=Info info=Info
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -107,15 +109,15 @@ pipelineOptions.validateButton=Validate
############# #############
navbar.favorite=Favorites navbar.favorite=Favorites
navbar.darkmode=الوضع الداكن navbar.darkmode=الوضع الداكن
navbar.language=Languages navbar.language=اللغات
navbar.settings=إعدادات navbar.settings=إعدادات
navbar.allTools=Tools navbar.allTools=أدوات
navbar.multiTool=Multi Tools navbar.multiTool=Multi Tools
navbar.sections.organize=Organize navbar.sections.organize=Organize
navbar.sections.convertTo=Convert to PDF navbar.sections.convertTo=تحويل الى PDF
navbar.sections.convertFrom=Convert from PDF navbar.sections.convertFrom=Convert from PDF
navbar.sections.security=Sign & Security navbar.sections.security=Sign & Security
navbar.sections.advance=Advanced navbar.sections.advance=متقدم
navbar.sections.edit=View & Edit navbar.sections.edit=View & Edit
############# #############
@@ -131,7 +133,7 @@ settings.downloadOption.2=فتح في نافذة جديدة
settings.downloadOption.3=تنزيل الملف settings.downloadOption.3=تنزيل الملف
settings.zipThreshold=ملفات مضغوطة عند تجاوز عدد الملفات التي تم تنزيلها settings.zipThreshold=ملفات مضغوطة عند تجاوز عدد الملفات التي تم تنزيلها
settings.signOut=Sign Out settings.signOut=Sign Out
settings.accountSettings=Account Settings settings.accountSettings=اعدادات الحساب
settings.bored.help=Enables easter egg game settings.bored.help=Enables easter egg game
settings.cacheInputs.name=Save form inputs settings.cacheInputs.name=Save form inputs
settings.cacheInputs.help=Enable to store previously used inputs for future runs settings.cacheInputs.help=Enable to store previously used inputs for future runs
@@ -139,10 +141,10 @@ settings.cacheInputs.help=Enable to store previously used inputs for future runs
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changePassword=You are using default login credentials. Please enter a new password changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=مستخدم جديد
changeCreds.oldPassword=Current Password changeCreds.oldPassword=كلمة المرور الحالية
changeCreds.newPassword=New Password changeCreds.newPassword=كلمة المرور الجديدة
changeCreds.confirmNewPassword=Confirm New Password changeCreds.confirmNewPassword=تأكيد كلمة المرور الجديدة
changeCreds.submit=Submit Changes changeCreds.submit=Submit Changes
@@ -173,6 +175,8 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
@@ -332,6 +336,10 @@ home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12) home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
certSign.tags=authenticate,PEM,P12,official,encrypt certSign.tags=authenticate,PEM,P12,official,encrypt
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Multi-Page Layout home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
pageLayout.tags=merge,composite,single-view,organize pageLayout.tags=merge,composite,single-view,organize
@@ -487,9 +495,9 @@ pdfToSinglePage.submit=Convert To Single Page
#pageExtracter #pageExtracter
pageExtracter.title=Extract Pages pageExtracter.title=استخراج الصفحات
pageExtracter.header=Extract Pages pageExtracter.header=استخراج الصفحات
pageExtracter.submit=Extract pageExtracter.submit=استخراج
pageExtracter.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1) pageExtracter.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
@@ -497,7 +505,7 @@ pageExtracter.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
getPdfInfo.title=Get Info on PDF getPdfInfo.title=Get Info on PDF
getPdfInfo.header=Get Info on PDF getPdfInfo.header=Get Info on PDF
getPdfInfo.submit=Get Info getPdfInfo.submit=Get Info
getPdfInfo.downloadJson=Download JSON getPdfInfo.downloadJson=تحميل JSON
#markdown-to-pdf #markdown-to-pdf
@@ -655,6 +663,13 @@ certSign.name=الاسم
certSign.submit=تسجيل PDF certSign.submit=تسجيل PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=إزالة الفراغات removeBlanks.title=إزالة الفراغات
removeBlanks.header=إزالة الصفحات الفارغة removeBlanks.header=إزالة الصفحات الفارغة
@@ -668,7 +683,7 @@ removeBlanks.submit=إزالة الفراغات
#removeAnnotations #removeAnnotations
removeAnnotations.title=Remove Annotations removeAnnotations.title=Remove Annotations
removeAnnotations.header=Remove Annotations removeAnnotations.header=Remove Annotations
removeAnnotations.submit=Remove removeAnnotations.submit=إزالة
#compare #compare
@@ -786,8 +801,9 @@ addImage.submit=إضافة صورة
#merge #merge
merge.title=دمج merge.title=دمج
merge.header=دمج ملفات PDF متعددة (2+) merge.header=دمج ملفات PDF متعددة (2+)
merge.sortByName=Sort by name merge.sortByName=الترتيب حسب الإسم
merge.sortByDate=Sort by date merge.sortByDate=الترتيب حسب التاريخ
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=دمج merge.submit=دمج
@@ -811,7 +827,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=أداة متعددة PDF multiTool.title=أداة متعددة PDF
multiTool.header=أداة متعددة PDF multiTool.header=أداة متعددة PDF
multiTool.uploadPrompts=File Name multiTool.uploadPrompts=إسم الملف
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@@ -852,7 +868,7 @@ imageToPDF.title=صورة إلى PDF
imageToPDF.header=صورة إلى PDF imageToPDF.header=صورة إلى PDF
imageToPDF.submit=تحول imageToPDF.submit=تحول
imageToPDF.selectLabel=Image Fit Options imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Fill Page imageToPDF.fillPage=امل الصفحة
imageToPDF.fitDocumentToImage=Fit Page to Image imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Maintain Aspect Ratios imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=دوران PDF تلقائيًا imageToPDF.selectText.2=دوران PDF تلقائيًا
@@ -891,7 +907,7 @@ addPassword.selectText.10=منع التعديل
addPassword.selectText.11=منع تعديل التعليقات التوضيحية addPassword.selectText.11=منع تعديل التعليقات التوضيحية
addPassword.selectText.12=منع الطباعة addPassword.selectText.12=منع الطباعة
addPassword.selectText.13=منع طباعة تنسيقات مختلفة addPassword.selectText.13=منع طباعة تنسيقات مختلفة
addPassword.selectText.14=Owner Password addPassword.selectText.14=كلمة مرور المالك
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers) addPassword.selectText.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.selectText.16=Restricts the opening of the document itself
addPassword.submit=تشفير addPassword.submit=تشفير
@@ -910,8 +926,8 @@ watermark.selectText.7=التعتيم (0٪ - 100٪):
watermark.selectText.8=Watermark Type: watermark.selectText.8=Watermark Type:
watermark.selectText.9=Watermark Image: watermark.selectText.9=Watermark Image:
watermark.submit=إضافة علامة مائية watermark.submit=إضافة علامة مائية
watermark.type.1=Text watermark.type.1=نص
watermark.type.2=Image watermark.type.2=صورة
#Change permissions #Change permissions
@@ -965,6 +981,7 @@ pdfToPDFA.credit=تستخدم هذه الخدمة OCRmyPDF لتحويل PDF / A.
pdfToPDFA.submit=تحويل pdfToPDFA.submit=تحويل
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1005,10 +1022,10 @@ PDFToXML.credit=تستخدم هذه الخدمة LibreOffice لتحويل الم
PDFToXML.submit=تحويل PDFToXML.submit=تحويل
#PDFToCSV #PDFToCSV
PDFToCSV.title=PDF ??? CSV PDFToCSV.title=PDF الى CSV
PDFToCSV.header=PDF ??? CSV PDFToCSV.header=PDF الى CSV
PDFToCSV.prompt=Choose page to extract table PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=?????? PDFToCSV.submit=تحويل
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count split-by-size-or-count.title=Split PDF by Size or Count
@@ -1050,11 +1067,11 @@ split-by-sections.merge=Merge Into One PDF
#printFile #printFile
printFile.title=Print File printFile.title=طباعة ملف
printFile.header=Print File to Printer printFile.header=طباعة ملف بالطابعة
printFile.selectText.1=Select File to Print printFile.selectText.1=تحديد ملف للطباعة
printFile.selectText.2=Enter Printer Name printFile.selectText.2=ادخل اسم الطابعة
printFile.submit=Print printFile.submit=طباعة
#licenses #licenses
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=License
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!

View File

@@ -55,12 +55,13 @@ userNotFoundMessage=Потребителят не е намерен
incorrectPasswordMessage=Текущата парола е неправилна. incorrectPasswordMessage=Текущата парола е неправилна.
usernameExistsMessage=Новият потребител вече съществува. usernameExistsMessage=Новият потребител вече съществува.
invalidUsernameMessage=Невалидно потребителско име, потребителското име може да съдържа само букви, цифри и следните специални знаци @._+- или трябва да е валиден имейл адрес. invalidUsernameMessage=Невалидно потребителско име, потребителското име може да съдържа само букви, цифри и следните специални знаци @._+- или трябва да е валиден имейл адрес.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Не може да се изтрие вписания в момента потребител. deleteCurrentUserMessage=Не може да се изтрие вписания в момента потребител.
deleteUsernameExistsMessage=Потребителското име не съществува и не може да бъде изтрито. deleteUsernameExistsMessage=Потребителското име не съществува и не може да бъде изтрито.
downgradeCurrentUserMessage=Не може да се понижи ролята на текущия потребител downgradeCurrentUserMessage=Не може да се понижи ролята на текущия потребител
downgradeCurrentUserLongMessage=Не може да се понижи ролята на текущия потребител. Следователно текущият потребител няма да бъде показан. downgradeCurrentUserLongMessage=Не може да се понижи ролята на текущия потребител. Следователно текущият потребител няма да бъде показан.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user. userAlreadyExistsOAuthMessage=Потребителят вече съществува като OAuth2 потребител.
userAlreadyExistsWebMessage=The user already exists as an web user. userAlreadyExistsWebMessage=Потребителят вече съществува като уеб-потребител.
error=Грешка error=Грешка
oops=Опаа! oops=Опаа!
help=Помощ help=Помощ
@@ -85,6 +86,7 @@ pipeline.defaultOption=Персонализиран
pipeline.submitButton=Подайте pipeline.submitButton=Подайте
pipeline.help=Pipeline Помощ pipeline.help=Pipeline Помощ
pipeline.scanHelp=Помощ за сканиране на папки pipeline.scanHelp=Помощ за сканиране на папки
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -105,18 +107,18 @@ pipelineOptions.validateButton=Валидирай
############# #############
# NAVBAR # # NAVBAR #
############# #############
navbar.favorite=Favorites navbar.favorite=Любими
navbar.darkmode=Тъмна тема navbar.darkmode=Тъмна тема
navbar.language=Languages navbar.language=Езици
navbar.settings=Настройки navbar.settings=Настройки
navbar.allTools=Tools navbar.allTools=Инструменти
navbar.multiTool=Multi Tools navbar.multiTool=Мулти инструменти
navbar.sections.organize=Organize navbar.sections.organize=Организирайте
navbar.sections.convertTo=Convert to PDF navbar.sections.convertTo=Преобразуване в PDF
navbar.sections.convertFrom=Convert from PDF navbar.sections.convertFrom=Преобразуване от PDF
navbar.sections.security=Sign & Security navbar.sections.security=Подписване и сигурност
navbar.sections.advance=Advanced navbar.sections.advance=Разширено
navbar.sections.edit=View & Edit navbar.sections.edit=Преглед и редактиране
############# #############
# SETTINGS # # SETTINGS #
@@ -173,6 +175,8 @@ adminUserSettings.header=Настройки за администраторск
adminUserSettings.admin=Администратор adminUserSettings.admin=Администратор
adminUserSettings.user=Потребител adminUserSettings.user=Потребител
adminUserSettings.addUser=Добавяне на нов потребител adminUserSettings.addUser=Добавяне на нов потребител
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Потребителското име може да съдържа само букви, цифри и следните специални символи @._+- или трябва да е валиден имейл адрес. adminUserSettings.usernameInfo=Потребителското име може да съдържа само букви, цифри и следните специални символи @._+- или трябва да е валиден имейл адрес.
adminUserSettings.roles=Роли adminUserSettings.roles=Роли
adminUserSettings.role=Роля adminUserSettings.role=Роля
@@ -185,7 +189,7 @@ adminUserSettings.internalApiUser=Вътрешен API потребител
adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане
adminUserSettings.submit=Съхранете потребителя adminUserSettings.submit=Съхранете потребителя
adminUserSettings.changeUserRole=Промяна на ролята на потребителя adminUserSettings.changeUserRole=Промяна на ролята на потребителя
adminUserSettings.authenticated=Authenticated adminUserSettings.authenticated=Удостоверен
############# #############
# HOME-PAGE # # HOME-PAGE #
@@ -267,7 +271,7 @@ home.fileToPDF.desc=Преобразуване почти всеки файл к
fileToPDF.tags=трансформация,формат,документ,изображение,слайд,текст,преобразуване,офис,документи,word,excel,powerpoint fileToPDF.tags=трансформация,формат,документ,изображение,слайд,текст,преобразуване,офис,документи,word,excel,powerpoint
home.ocr.title=OCR / Почистващи сканирания home.ocr.title=OCR / Почистващи сканирания
home.ocr.desc=Почистване, сканира и открива текст от изображения към PDF и го добавя отново като текст. home.ocr.desc=Почиства, сканира и открива текст от изображения в PDF и го добавя отново като текст.
ocr.tags=разпознаване,текст,изображение,сканиране,четене,идентифициране,откриване,редактиране ocr.tags=разпознаване,текст,изображение,сканиране,четене,идентифициране,откриване,редактиране
@@ -313,7 +317,7 @@ home.flatten.desc=Премахнете всички интерактивни е
flatten.tags=статичен,деактивиран,неинтерактивен,рационализиран flatten.tags=статичен,деактивиран,неинтерактивен,рационализиран
home.repair.title=Поправи home.repair.title=Поправи
home.repair.desc=Опитва се да поправи повреден/счупен PDF home.repair.desc=Опитва се да поправи повреден PDF
repair.tags=поправка,възстановяване,корекция,възстановяване repair.tags=поправка,възстановяване,корекция,възстановяване
home.removeBlanks.title=Премахване на празни страници home.removeBlanks.title=Премахване на празни страници
@@ -332,6 +336,10 @@ home.certSign.title=Подпишете със сертификат
home.certSign.desc=Подписва PDF със сертификат/ключ (PEM/P12) home.certSign.desc=Подписва PDF със сертификат/ключ (PEM/P12)
certSign.tags=удостоверяване,PEM,P12,официален,шифроване certSign.tags=удостоверяване,PEM,P12,официален,шифроване
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Оформление с няколко страници home.pageLayout.title=Оформление с няколко страници
home.pageLayout.desc=Слейте няколко страници от PDF документ в една страница home.pageLayout.desc=Слейте няколко страници от PDF документ в една страница
pageLayout.tags=сливане,комбиниран,единичен изглед,организиране pageLayout.tags=сливане,комбиниран,единичен изглед,организиране
@@ -364,7 +372,7 @@ home.autoSplitPDF.title=Автоматично разделяне на стра
home.autoSplitPDF.desc=Автоматично разделяне на сканиран PDF файл с QR код за разделяне на физически сканирани страници home.autoSplitPDF.desc=Автоматично разделяне на сканиран PDF файл с QR код за разделяне на физически сканирани страници
autoSplitPDF.tags=QR-базиран,отделен,сканиране-сегмент,организиране autoSplitPDF.tags=QR-базиран,отделен,сканиране-сегмент,организиране
home.sanitizePdf.title=Дезинфенкцирам home.sanitizePdf.title=Обеззаразяване
home.sanitizePdf.desc=Премахване на скриптове и други елементи от PDF файлове home.sanitizePdf.desc=Премахване на скриптове и други елементи от PDF файлове
sanitizePdf.tags=чисти,сигурни,безопасни,премахване-заплахи sanitizePdf.tags=чисти,сигурни,безопасни,премахване-заплахи
@@ -382,8 +390,8 @@ home.MarkdownToPDF.desc=Преобразува всеки Markdown файл къ
MarkdownToPDF.tags=маркиране,уеб-съдържание,трансформация,преобразуване MarkdownToPDF.tags=маркиране,уеб-съдържание,трансформация,преобразуване
home.getPdfInfo.title=Вземете ЦЯЛАТА информация към PDF home.getPdfInfo.title=Вземете ЦЯЛАТА информация от PDF
home.getPdfInfo.desc=Взема всяка възможна информация от PDF файлове home.getPdfInfo.desc=Взима всяка възможна информация от PDF файлове
getPdfInfo.tags=информация,данни,статистики,статистика getPdfInfo.tags=информация,данни,статистики,статистика
@@ -405,7 +413,7 @@ home.autoRedact.title=Автоматично редактиране
home.autoRedact.desc=Автоматично редактира (зачернява) текст в PDF въз основа на въведен текст home.autoRedact.desc=Автоматично редактира (зачернява) текст в PDF въз основа на въведен текст
autoRedact.tags=Редактиране,Скриване,затъмняване,черен,маркер,скрит autoRedact.tags=Редактиране,Скриване,затъмняване,черен,маркер,скрит
home.tableExtraxt.title=PDF to CSV home.tableExtraxt.title=PDF в CSV
home.tableExtraxt.desc=Извлича таблици от PDF, като ги конвертира в CSV home.tableExtraxt.desc=Извлича таблици от PDF, като ги конвертира в CSV
tableExtraxt.tags=CSV,извличане на таблица,извличане,конвертиране tableExtraxt.tags=CSV,извличане на таблица,извличане,конвертиране
@@ -452,12 +460,12 @@ login.locked=Вашият акаунт е заключен.
login.signinTitle=Моля впишете се login.signinTitle=Моля впишете се
login.ssoSignIn=Влизане чрез еднократно влизане login.ssoSignIn=Влизане чрез еднократно влизане
login.oauth2AutoCreateDisabled=OAUTH2 Автоматично създаване на потребител е деактивирано login.oauth2AutoCreateDisabled=OAUTH2 Автоматично създаване на потребител е деактивирано
login.oauth2RequestNotFound=Authorization request not found login.oauth2RequestNotFound=Заявката за оторизация не е намерена
login.oauth2InvalidUserInfoResponse=Invalid User Info Response login.oauth2InvalidUserInfoResponse=Невалидна информация за потребителя
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Невалидна заявка
login.oauth2AccessDenied=Access Denied login.oauth2AccessDenied=Отказан достъп
login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidTokenResponse=Невалиден отговор на токена
login.oauth2InvalidIdToken=Invalid Id Token login.oauth2InvalidIdToken=Невалиден токен за идентификатор
#auto-redact #auto-redact
@@ -638,7 +646,7 @@ scalePages.submit=Подайте
#certSign #certSign
certSign.title=Подписване на сертификат certSign.title=Подписване със сертификат
certSign.header=Подпишете PDF с вашия сертификат (В процес на работа) certSign.header=Подпишете PDF с вашия сертификат (В процес на работа)
certSign.selectPDF=Изберете PDF файл за подписване: certSign.selectPDF=Изберете PDF файл за подписване:
certSign.jksNote=Забележка: Ако вашият тип сертификат не е в списъка по-долу, моля, конвертирайте го във файл на Java Keystore (.jks) с помощта на инструмента за команден ред keytool. След това изберете опцията за .jks файл по-долу. certSign.jksNote=Забележка: Ако вашият тип сертификат не е в списъка по-долу, моля, конвертирайте го във файл на Java Keystore (.jks) с помощта на инструмента за команден ред keytool. След това изберете опцията за .jks файл по-долу.
@@ -655,6 +663,13 @@ certSign.name=Име
certSign.submit=Подпишете PDF certSign.submit=Подпишете PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Премахване на празни места removeBlanks.title=Премахване на празни места
removeBlanks.header=Премахване на празни страници removeBlanks.header=Премахване на празни страници
@@ -758,7 +773,7 @@ extractImages.submit=Извличане
fileToPDF.title=Файл към PDF fileToPDF.title=Файл към PDF
fileToPDF.header=Конвертирайте всеки файл към PDF fileToPDF.header=Конвертирайте всеки файл към PDF
fileToPDF.credit=Тази услуга използва LibreOffice и Unoconv за преобразуване на файлове. fileToPDF.credit=Тази услуга използва LibreOffice и Unoconv за преобразуване на файлове.
fileToPDF.supportedFileTypesInfo=Supported File types fileToPDF.supportedFileTypesInfo=Поддържание файлови типове
fileToPDF.supportedFileTypes=Поддържаните типове файлове трябва да включват по-долу, но за пълен актуализиран списък на поддържаните формати, моля, вижте документацията на LibreOffice fileToPDF.supportedFileTypes=Поддържаните типове файлове трябва да включват по-долу, но за пълен актуализиран списък на поддържаните формати, моля, вижте документацията на LibreOffice
fileToPDF.submit=Преобразуване към PDF fileToPDF.submit=Преобразуване към PDF
@@ -767,10 +782,10 @@ fileToPDF.submit=Преобразуване към PDF
compress.title=Компресиране compress.title=Компресиране
compress.header=Компресиране на PDF compress.header=Компресиране на PDF
compress.credit=Тази услуга използва Ghostscript за PDF компресиране/оптимизиране. compress.credit=Тази услуга използва Ghostscript за PDF компресиране/оптимизиране.
compress.selectText.1=Ръчен режим - От 1 до 4 compress.selectText.1=Ръчен режим - от 1 до 4
compress.selectText.2=Ниво на оптимизация: compress.selectText.2=Ниво на оптимизация:
compress.selectText.3=4 (Ужасно за текстови изображения) compress.selectText.3=4 (Ужасно за текстови изображения)
compress.selectText.4=Автоматичен режим - Автоматично настройва качеството, за да получи PDF точен размер compress.selectText.4=Автоматичен режим - Автоматично настройва качеството, за да получи PDF с точен размер
compress.selectText.5=Очакван PDF размер (напр. 25МБ, 10.8МБ, 25КБ) compress.selectText.5=Очакван PDF размер (напр. 25МБ, 10.8МБ, 25КБ)
compress.submit=Компресиране compress.submit=Компресиране
@@ -788,6 +803,7 @@ merge.title=Обединяване
merge.header=Обединяване на множество PDF файлове (2+) merge.header=Обединяване на множество PDF файлове (2+)
merge.sortByName=Сортиране по име merge.sortByName=Сортиране по име
merge.sortByDate=Сортиране по дата merge.sortByDate=Сортиране по дата
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Обединяване merge.submit=Обединяване
@@ -811,7 +827,7 @@ pdfOrganiser.placeholder=(напр. 1,3,2 или 4-8,2,10-12 или 2n-1)
#multiTool #multiTool
multiTool.title=PDF Мулти инструмент multiTool.title=PDF Мулти инструмент
multiTool.header=PDF Мулти инструмент multiTool.header=PDF Мулти инструмент
multiTool.uploadPrompts=File Name multiTool.uploadPrompts=Име на файл
#view pdf #view pdf
viewPdf.title=Преглед на PDF viewPdf.title=Преглед на PDF
@@ -910,8 +926,8 @@ watermark.selectText.7=Непрозрачност (0% - 100%):
watermark.selectText.8=Тип воден знак: watermark.selectText.8=Тип воден знак:
watermark.selectText.9=Изображение за воден знак: watermark.selectText.9=Изображение за воден знак:
watermark.submit=Добавяне на воден знак watermark.submit=Добавяне на воден знак
watermark.type.1=Text watermark.type.1=Текст
watermark.type.2=Image watermark.type.2=Изображение
#Change permissions #Change permissions
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Тази услуга използва OCRmyPDF за PDF/A пр
pdfToPDFA.submit=Преобразуване pdfToPDFA.submit=Преобразуване
pdfToPDFA.tip=В момента не работи за няколко входа наведнъж pdfToPDFA.tip=В момента не работи за няколко входа наведнъж
pdfToPDFA.outputFormat=Изходен формат pdfToPDFA.outputFormat=Изходен формат
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Модул
licenses.version=Версия licenses.version=Версия
licenses.license=Лиценз licenses.license=Лиценз
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Извинете за проблема! error.sorry=Извинете за проблема!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=No es pot reduir la funció de l'usuari actual downgradeCurrentUserMessage=No es pot reduir la funció de l'usuari actual
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Usuari Admin Opcions Control
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Usuari adminUserSettings.user=Usuari
adminUserSettings.addUser=Afegir Usuari adminUserSettings.addUser=Afegir Usuari
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Rols adminUserSettings.roles=Rols
adminUserSettings.role=Rol adminUserSettings.role=Rol
@@ -332,6 +336,10 @@ home.certSign.title=Signa amb Certificat
home.certSign.desc=Sign PDF amb Certificate/Clau (PEM/P12) home.certSign.desc=Sign PDF amb Certificate/Clau (PEM/P12)
certSign.tags=authentica,PEM,P12,official,encripta certSign.tags=authentica,PEM,P12,official,encripta
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Multi-Page Layout home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
pageLayout.tags=merge,composite,single-view,organize pageLayout.tags=merge,composite,single-view,organize
@@ -655,6 +663,13 @@ certSign.name=Nom
certSign.submit=Firma PDF certSign.submit=Firma PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Elimina els espais en blanc removeBlanks.title=Elimina els espais en blanc
removeBlanks.header=Elimina les pàgines en blanc removeBlanks.header=Elimina les pàgines en blanc
@@ -788,6 +803,7 @@ merge.title=Fusiona
merge.header=Fusiona múltiples PDFs (2+) merge.header=Fusiona múltiples PDFs (2+)
merge.sortByName=Sort by name merge.sortByName=Sort by name
merge.sortByDate=Sort by date merge.sortByDate=Sort by date
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Fusiona merge.submit=Fusiona
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Utilitza OCRmyPDF per la conversió a PDF/A
pdfToPDFA.submit=Converteix pdfToPDFA.submit=Converteix
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=License
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!

View File

@@ -1,7 +1,7 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr = left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
language.direction=ltr language.direction=ltr
pdfPrompt=Vyberte PDF soubory pdfPrompt=Vyberte PDF soubory
@@ -26,7 +26,7 @@ bored=Nudíte se při čekání?
alphabet=Abeceda alphabet=Abeceda
downloadPdf=Stáhnout PDF downloadPdf=Stáhnout PDF
text=Text text=Text
font=Font font=Písmo
selectFillter=-- Vyberte -- selectFillter=-- Vyberte --
pageNum=Číslo stránky pageNum=Číslo stránky
sizes.small=Malé sizes.small=Malé
@@ -55,6 +55,7 @@ userNotFoundMessage=Uživatel nenalezen.
incorrectPasswordMessage=Současné heslo není správné. incorrectPasswordMessage=Současné heslo není správné.
usernameExistsMessage=Nové uživatelské jméno již existuje. usernameExistsMessage=Nové uživatelské jméno již existuje.
invalidUsernameMessage=Nesprávné uživatelské jméno, smí obsahovat pouze písmena, číslice a následující speciální znaky @._+- nebo musí být validní emailová adresa. invalidUsernameMessage=Nesprávné uživatelské jméno, smí obsahovat pouze písmena, číslice a následující speciální znaky @._+- nebo musí být validní emailová adresa.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Nelze smazat aktuální přihlášeného uživatele. deleteCurrentUserMessage=Nelze smazat aktuální přihlášeného uživatele.
deleteUsernameExistsMessage=Uživatelské jméno neexistuje a nelze ho smazat. deleteUsernameExistsMessage=Uživatelské jméno neexistuje a nelze ho smazat.
downgradeCurrentUserMessage=Nelze snížit roli aktuálního uživatele. downgradeCurrentUserMessage=Nelze snížit roli aktuálního uživatele.
@@ -85,6 +86,7 @@ pipeline.defaultOption=Vlastní
pipeline.submitButton=Odeslat pipeline.submitButton=Odeslat
pipeline.help=Pomoc s pipeline pipeline.help=Pomoc s pipeline
pipeline.scanHelp=Pomoc se skenováním adresáře pipeline.scanHelp=Pomoc se skenováním adresáře
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Uživatel adminUserSettings.user=Uživatel
adminUserSettings.addUser=Přidat Nového Uživatele adminUserSettings.addUser=Přidat Nového Uživatele
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Uživatelské Jméno může obsahovat pouze písmena, čísla a následující speciální znaky @._+- nebo musí být správná emailová adresa. adminUserSettings.usernameInfo=Uživatelské Jméno může obsahovat pouze písmena, čísla a následující speciální znaky @._+- nebo musí být správná emailová adresa.
adminUserSettings.roles=Role adminUserSettings.roles=Role
adminUserSettings.role=Role adminUserSettings.role=Role
@@ -190,7 +194,7 @@ adminUserSettings.authenticated=Ověřeno
############# #############
# HOME-PAGE # # HOME-PAGE #
############# #############
home.desc= Vaše lokálně hostované jednotné kontaktní místo pro všechny vaše potřeby ve formátu PDF home.desc=Vaše lokálně hostované jednotné kontaktní místo pro všechny vaše potřeby ve formátu PDF
home.searchBar=Hledej funkce... home.searchBar=Hledej funkce...
@@ -224,7 +228,7 @@ home.pdfToImage.desc=Konvertovat PDF na obrázek. (PNG, JPEG, GIF)
pdfToImage.tags=konverze,img,jpg,obrázek,fotka pdfToImage.tags=konverze,img,jpg,obrázek,fotka
home.pdfOrganiser.title=Organizovat home.pdfOrganiser.title=Organizovat
home.pdfOrganiser.desc=Odebrat/Přeskupit stránky v jakémkoli pořadí home.pdfOrganiser.desc=Odebrat/Přeskupit stránky v jakémkoli pořadí
pdfOrganiser.tags=dvojitý,sudý,lichý,seřadit,přesunout pdfOrganiser.tags=dvojitý,sudý,lichý,seřadit,přesunout
@@ -332,6 +336,10 @@ home.certSign.title=Podpis s certifikátem
home.certSign.desc=Podpis PDF s certifikátem/klíčem (PEM/P12) home.certSign.desc=Podpis PDF s certifikátem/klíčem (PEM/P12)
certSign.tags=autentizace,PEM,P12,oficiální,šifrování certSign.tags=autentizace,PEM,P12,oficiální,šifrování
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Vícestránkové rozložení home.pageLayout.title=Vícestránkové rozložení
home.pageLayout.desc=Sloučení více stránek dokumentu PDF do jedné stránky home.pageLayout.desc=Sloučení více stránek dokumentu PDF do jedné stránky
pageLayout.tags=sloučit,kompozitní,jedno zobrazení,organizovat pageLayout.tags=sloučit,kompozitní,jedno zobrazení,organizovat
@@ -655,6 +663,13 @@ certSign.name=Název
certSign.submit=Podepsat PDF certSign.submit=Podepsat PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Odebrat prázdné stránky removeBlanks.title=Odebrat prázdné stránky
removeBlanks.header=Odebrat prázdné stránky removeBlanks.header=Odebrat prázdné stránky
@@ -710,7 +725,7 @@ repair.submit=Opravit
#flatten #flatten
flatten.title=Zploštit flatten.title=Zploštit
flatten.header=Zploštit PDF flatten.header=Zploštit PDF
flatten.flattenOnlyForms=Zploštit pouze formuláře flatten.flattenOnlyForms=Zploštit pouze formuláře
flatten.submit=Zploštit flatten.submit=Zploštit
@@ -788,6 +803,7 @@ merge.title=Sloučit
merge.header=Sloučit více PDF (2+) merge.header=Sloučit více PDF (2+)
merge.sortByName=Seřadit podle názvu merge.sortByName=Seřadit podle názvu
merge.sortByDate=Seřadit podle data merge.sortByDate=Seřadit podle data
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Sloučit merge.submit=Sloučit
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Tato služba používá OCRmyPDF pro konverzi do formátu PDF/A
pdfToPDFA.submit=Převést pdfToPDFA.submit=Převést
pdfToPDFA.tip=V současné době nepracuje pro více vstupů najednou pdfToPDFA.tip=V současné době nepracuje pro více vstupů najednou
pdfToPDFA.outputFormat=Výstupní formát pdfToPDFA.outputFormat=Výstupní formát
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Modul
licenses.version=Verze licenses.version=Verze
licenses.license=Licence licenses.license=Licence
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Omlouváme se za potíže! error.sorry=Omlouváme se za potíže!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=Benutzer nicht gefunden.
incorrectPasswordMessage=Das Passwort ist falsch. incorrectPasswordMessage=Das Passwort ist falsch.
usernameExistsMessage=Neuer Benutzername existiert bereits. usernameExistsMessage=Neuer Benutzername existiert bereits.
invalidUsernameMessage=Ungültiger Benutzername. Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein. invalidUsernameMessage=Ungültiger Benutzername. Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein.
confirmPasswordErrorMessage=„Neues Passwort“ und „Neues Passwort bestätigen“ müssen übereinstimmen.
deleteCurrentUserMessage=Der aktuell angemeldete Benutzer kann nicht gelöscht werden. deleteCurrentUserMessage=Der aktuell angemeldete Benutzer kann nicht gelöscht werden.
deleteUsernameExistsMessage=Der Benutzername existiert nicht und kann nicht gelöscht werden. deleteUsernameExistsMessage=Der Benutzername existiert nicht und kann nicht gelöscht werden.
downgradeCurrentUserMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden downgradeCurrentUserMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden
@@ -71,7 +72,7 @@ visitGithub=GitHub-Repository besuchen
donate=Spenden donate=Spenden
color=Farbe color=Farbe
sponsor=Sponsor sponsor=Sponsor
info=Die Info info=Informationen
@@ -85,6 +86,7 @@ pipeline.defaultOption=Benutzerdefiniert
pipeline.submitButton=Speichern pipeline.submitButton=Speichern
pipeline.help=Hilfe für Pipeline pipeline.help=Hilfe für Pipeline
pipeline.scanHelp=Hilfe zum Ordnerscan pipeline.scanHelp=Hilfe zum Ordnerscan
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Administrator-Benutzerkontrolle
adminUserSettings.admin=Administrator adminUserSettings.admin=Administrator
adminUserSettings.user=Benutzer adminUserSettings.user=Benutzer
adminUserSettings.addUser=Neuen Benutzer hinzufügen adminUserSettings.addUser=Neuen Benutzer hinzufügen
adminUserSettings.deleteUser=Benutzer löschen
adminUserSettings.confirmDeleteUser=Soll der Benutzer gelöscht werden?
adminUserSettings.usernameInfo=Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein. adminUserSettings.usernameInfo=Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein.
adminUserSettings.roles=Rollen adminUserSettings.roles=Rollen
adminUserSettings.role=Rolle adminUserSettings.role=Rolle
@@ -332,6 +336,10 @@ home.certSign.title=Mit Zertifikat signieren
home.certSign.desc=Ein PDF mit einem Zertifikat/Schlüssel (PEM/P12) signieren home.certSign.desc=Ein PDF mit einem Zertifikat/Schlüssel (PEM/P12) signieren
certSign.tags=authentifizieren,pem,p12,offiziell,verschlüsseln certSign.tags=authentifizieren,pem,p12,offiziell,verschlüsseln
home.removeCertSign.title=Zertifikatsignatur entfernen
home.removeCertSign.desc=Zertifikatsignatur aus PDF entfernen
removeCertSign.tags=authentifizieren,PEM,P12,offiziell,entschlüsseln,decrypt
home.pageLayout.title=Mehrseitiges Layout home.pageLayout.title=Mehrseitiges Layout
home.pageLayout.desc=Mehrere Seiten eines PDF zu einer Seite zusammenführen home.pageLayout.desc=Mehrere Seiten eines PDF zu einer Seite zusammenführen
pageLayout.tags=zusammenführen,zusammensetzen,einzelansicht,organisieren pageLayout.tags=zusammenführen,zusammensetzen,einzelansicht,organisieren
@@ -655,6 +663,13 @@ certSign.name=Name
certSign.submit=PDF signieren certSign.submit=PDF signieren
#removeCertSign
removeCertSign.title=Zertifikatsignatur entfernen
removeCertSign.header=Digitales Zertifikat aus dem PDF entfernen
removeCertSign.selectPDF=PDF-Datei auswählen:
removeCertSign.submit=Signatur entfernen
#removeBlanks #removeBlanks
removeBlanks.title=Leere Seiten entfernen removeBlanks.title=Leere Seiten entfernen
removeBlanks.header=Leere Seiten entfernen removeBlanks.header=Leere Seiten entfernen
@@ -788,6 +803,7 @@ merge.title=Zusammenführen
merge.header=Mehrere PDFs zusammenführen (2+) merge.header=Mehrere PDFs zusammenführen (2+)
merge.sortByName=Nach Namen sortieren merge.sortByName=Nach Namen sortieren
merge.sortByDate=Nach Datum sortieren merge.sortByDate=Nach Datum sortieren
merge.removeCertSign=Digitale Signatur in der zusammengeführten Datei entfernen?
merge.submit=Zusammenführen merge.submit=Zusammenführen
@@ -805,6 +821,7 @@ pdfOrganiser.mode.6=Ungerade-Gerade-Teilung
pdfOrganiser.mode.7=Erste entfernen pdfOrganiser.mode.7=Erste entfernen
pdfOrganiser.mode.8=Letzte entfernen pdfOrganiser.mode.8=Letzte entfernen
pdfOrganiser.mode.9=Erste und letzte entfernen pdfOrganiser.mode.9=Erste und letzte entfernen
pdfOrganiser.mode.10=Ungerade-Gerade-Zusammenführung
pdfOrganiser.placeholder=(z.B. 1,3,2 oder 4-8,2,10-12 oder 2n-1) pdfOrganiser.placeholder=(z.B. 1,3,2 oder 4-8,2,10-12 oder 2n-1)
@@ -965,6 +982,7 @@ pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung
pdfToPDFA.submit=Konvertieren pdfToPDFA.submit=Konvertieren
pdfToPDFA.tip=Dieser Dienst kann nur einzelne Eingangsdateien verarbeiten. pdfToPDFA.tip=Dieser Dienst kann nur einzelne Eingangsdateien verarbeiten.
pdfToPDFA.outputFormat=Ausgabeformat pdfToPDFA.outputFormat=Ausgabeformat
pdfToPDFA.pdfWithDigitalSignature=Das PDF enthält eine digitale Signatur. Sie wird im nächsten Schritt entfernt.
#PDFToWord #PDFToWord
@@ -1065,6 +1083,15 @@ licenses.module=Modul
licenses.version=Version licenses.version=Version
licenses.license=Lizenz licenses.license=Lizenz
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Entschuldigung für das Problem! error.sorry=Entschuldigung für das Problem!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=Ο χρήστης δεν βρέθηκε.
incorrectPasswordMessage=Ο τρέχων κωδικός πρόσβασης είναι λανθασμένος. incorrectPasswordMessage=Ο τρέχων κωδικός πρόσβασης είναι λανθασμένος.
usernameExistsMessage=Το νέο όνομα χρήστη υπάρχει ήδη. usernameExistsMessage=Το νέο όνομα χρήστη υπάρχει ήδη.
invalidUsernameMessage=Μη έγκυρο όνομα χρήστη, όνομα χρήστη μπορεί να περιέχει μόνο γράμματα, αριθμούς και τους ακόλουθους ειδικούς χαρακτήρες @._+- ή πρέπει να είναι έγκυρη διεύθυνση email. invalidUsernameMessage=Μη έγκυρο όνομα χρήστη, όνομα χρήστη μπορεί να περιέχει μόνο γράμματα, αριθμούς και τους ακόλουθους ειδικούς χαρακτήρες @._+- ή πρέπει να είναι έγκυρη διεύθυνση email.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Δεν είναι δυνατή η διαγραφή του τρέχοντος συνδεδεμένου χρήστη. deleteCurrentUserMessage=Δεν είναι δυνατή η διαγραφή του τρέχοντος συνδεδεμένου χρήστη.
deleteUsernameExistsMessage=Το όνομα χρήστη δεν υπάρχει και δεν μπορεί να διαγραφεί. deleteUsernameExistsMessage=Το όνομα χρήστη δεν υπάρχει και δεν μπορεί να διαγραφεί.
downgradeCurrentUserMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη downgradeCurrentUserMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Υποβολή pipeline.submitButton=Υποβολή
pipeline.help=Βοήθεια για το Pipeline pipeline.help=Βοήθεια για το Pipeline
pipeline.scanHelp=Βοήθεια για Σάρωση Φακέλων pipeline.scanHelp=Βοήθεια για Σάρωση Φακέλων
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Ρυθμίσεις ελέγχου Διαχειριστ
adminUserSettings.admin=Διαχειριστής adminUserSettings.admin=Διαχειριστής
adminUserSettings.user=Χρήστης adminUserSettings.user=Χρήστης
adminUserSettings.addUser=Προσθήκη νέου Χρήστη adminUserSettings.addUser=Προσθήκη νέου Χρήστη
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Ρόλοι adminUserSettings.roles=Ρόλοι
adminUserSettings.role=Ρόλος adminUserSettings.role=Ρόλος
@@ -332,6 +336,10 @@ home.certSign.title=Υπογραφή με Πιστοποιητικό
home.certSign.desc=Υπογραφή ενός PDF αρχείου με ένα Πιστοποιητικό/Κλειδί (PEM/P12) home.certSign.desc=Υπογραφή ενός PDF αρχείου με ένα Πιστοποιητικό/Κλειδί (PEM/P12)
certSign.tags=authenticate,PEM,P12,official,encrypt certSign.tags=authenticate,PEM,P12,official,encrypt
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Διάταξη πολλών σελίδων home.pageLayout.title=Διάταξη πολλών σελίδων
home.pageLayout.desc=Συγχώνευση πολλαπλών σελίδων ενός εγγράφου PDF σε μία μόνο σελίδα home.pageLayout.desc=Συγχώνευση πολλαπλών σελίδων ενός εγγράφου PDF σε μία μόνο σελίδα
pageLayout.tags=merge,composite,single-view,organize pageLayout.tags=merge,composite,single-view,organize
@@ -655,6 +663,13 @@ certSign.name=Όνομα
certSign.submit=Υπογραφή PDF certSign.submit=Υπογραφή PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Αφαίρεση Κενών removeBlanks.title=Αφαίρεση Κενών
removeBlanks.header=Αφαίρεση Κενών Σελίδων removeBlanks.header=Αφαίρεση Κενών Σελίδων
@@ -788,6 +803,7 @@ merge.title=Συγχώνευση
merge.header=Συγχώνευση πολλαπλών PDFs (2+) merge.header=Συγχώνευση πολλαπλών PDFs (2+)
merge.sortByName=Ταξινόμηση με βάση το Όνομα merge.sortByName=Ταξινόμηση με βάση το Όνομα
merge.sortByDate=Ταξινόμηση με βάση την Ημερομηνία merge.sortByDate=Ταξινόμηση με βάση την Ημερομηνία
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Συγχώνευση merge.submit=Συγχώνευση
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Αυτή η υπηρεσία χρησιμοποιεί OCRmyPDF
pdfToPDFA.submit=Μετατροπή pdfToPDFA.submit=Μετατροπή
pdfToPDFA.tip=Προς το παρόν δεν λειτουργεί για πολλαπλές εισόδους ταυτόχρονα pdfToPDFA.tip=Προς το παρόν δεν λειτουργεί για πολλαπλές εισόδους ταυτόχρονα
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Εκδοχή licenses.version=Εκδοχή
licenses.license=Άδεια licenses.license=Άδεια
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Συγγνώμη για το ζήτημα! error.sorry=Συγγνώμη για το ζήτημα!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Cannot downgrade current user's role downgradeCurrentUserMessage=Cannot downgrade current user's role
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
@@ -332,6 +336,10 @@ home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12) home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
certSign.tags=authenticate,PEM,P12,official,encrypt certSign.tags=authenticate,PEM,P12,official,encrypt
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Multi-Page Layout home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
pageLayout.tags=merge,composite,single-view,organize pageLayout.tags=merge,composite,single-view,organize
@@ -655,6 +663,13 @@ certSign.name=Name
certSign.submit=Sign PDF certSign.submit=Sign PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Remove Blanks removeBlanks.title=Remove Blanks
removeBlanks.header=Remove Blank Pages removeBlanks.header=Remove Blank Pages
@@ -788,6 +803,7 @@ merge.title=Merge
merge.header=Merge multiple PDFs (2+) merge.header=Merge multiple PDFs (2+)
merge.sortByName=Sort by name merge.sortByName=Sort by name
merge.sortByDate=Sort by date merge.sortByDate=Sort by date
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Merge merge.submit=Merge
@@ -805,6 +821,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1) pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -965,6 +982,7 @@ pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
pdfToPDFA.submit=Convert pdfToPDFA.submit=Convert
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1058,12 +1076,21 @@ printFile.submit=Print
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licences
licenses.title=3rd Party Licenses licenses.title=3rd Party Licences
licenses.header=3rd Party Licenses licenses.header=3rd Party Licences
licenses.module=Module licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=Licence
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Cannot downgrade current user's role downgradeCurrentUserMessage=Cannot downgrade current user's role
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
@@ -332,6 +336,10 @@ home.certSign.title=Sign with Certificate
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12) home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
certSign.tags=authenticate,PEM,P12,official,encrypt certSign.tags=authenticate,PEM,P12,official,encrypt
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Multi-Page Layout home.pageLayout.title=Multi-Page Layout
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
pageLayout.tags=merge,composite,single-view,organize pageLayout.tags=merge,composite,single-view,organize
@@ -655,6 +663,13 @@ certSign.name=Name
certSign.submit=Sign PDF certSign.submit=Sign PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Remove Blanks removeBlanks.title=Remove Blanks
removeBlanks.header=Remove Blank Pages removeBlanks.header=Remove Blank Pages
@@ -788,6 +803,7 @@ merge.title=Merge
merge.header=Merge multiple PDFs (2+) merge.header=Merge multiple PDFs (2+)
merge.sortByName=Sort by name merge.sortByName=Sort by name
merge.sortByDate=Sort by date merge.sortByDate=Sort by date
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Merge merge.submit=Merge
@@ -805,6 +821,7 @@ pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Remove First pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Remove Last pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Remove First and Last pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1) pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
@@ -965,6 +982,7 @@ pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
pdfToPDFA.submit=Convert pdfToPDFA.submit=Convert
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1083,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=License
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=Usuario no encontrado.
incorrectPasswordMessage=La contraseña actual no es correcta. incorrectPasswordMessage=La contraseña actual no es correcta.
usernameExistsMessage=El nuevo nombre de usuario está en uso. usernameExistsMessage=El nuevo nombre de usuario está en uso.
invalidUsernameMessage=Nombre de usuario no válido, el nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida. invalidUsernameMessage=Nombre de usuario no válido, el nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actualmente en uso. deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actualmente en uso.
deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse. deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse.
downgradeCurrentUserMessage=No se puede degradar el rol del usuario actual downgradeCurrentUserMessage=No se puede degradar el rol del usuario actual
@@ -85,6 +86,7 @@ pipeline.defaultOption=Personalizar
pipeline.submitButton=Enviar pipeline.submitButton=Enviar
pipeline.help=Ayuda de Canalización pipeline.help=Ayuda de Canalización
pipeline.scanHelp=Ayuda de escaneado de carpetas pipeline.scanHelp=Ayuda de escaneado de carpetas
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Configuración de control de usuario administrador
adminUserSettings.admin=Administrador adminUserSettings.admin=Administrador
adminUserSettings.user=Usuario adminUserSettings.user=Usuario
adminUserSettings.addUser=Añadir Nuevo Usuario adminUserSettings.addUser=Añadir Nuevo Usuario
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=El nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida. adminUserSettings.usernameInfo=El nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Rol adminUserSettings.role=Rol
@@ -332,6 +336,10 @@ home.certSign.title=Firmar con certificado
home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12) home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12)
certSign.tags=autentificar,PEM,P12,oficial,encriptar certSign.tags=autentificar,PEM,P12,oficial,encriptar
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Diseño de varias páginas home.pageLayout.title=Diseño de varias páginas
home.pageLayout.desc=Unir varias páginas de un documento PDF en una sola página home.pageLayout.desc=Unir varias páginas de un documento PDF en una sola página
pageLayout.tags=unir,compuesto,vista única,organizar pageLayout.tags=unir,compuesto,vista única,organizar
@@ -655,6 +663,13 @@ certSign.name=Nombre
certSign.submit=Firmar PDF certSign.submit=Firmar PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Eliminar espacios en blanco removeBlanks.title=Eliminar espacios en blanco
removeBlanks.header=Eliminar páginas en blanco removeBlanks.header=Eliminar páginas en blanco
@@ -788,6 +803,7 @@ merge.title=Unir
merge.header=Unir múltiples PDFs (2+) merge.header=Unir múltiples PDFs (2+)
merge.sortByName=Ordenar por nombre merge.sortByName=Ordenar por nombre
merge.sortByDate=Ordenar por fecha merge.sortByDate=Ordenar por fecha
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Unir merge.submit=Unir
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
pdfToPDFA.submit=Convertir pdfToPDFA.submit=Convertir
pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Módulo
licenses.version=Versión licenses.version=Versión
licenses.license=Licencia licenses.license=Licencia
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=¡Perdón por el fallo! error.sorry=¡Perdón por el fallo!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Ezin da uneko erabiltzailearen rola jaitsi downgradeCurrentUserMessage=Ezin da uneko erabiltzailearen rola jaitsi
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Admin Erabiltzailearen Ezarpenen Kontrolak
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Erabiltzaile adminUserSettings.user=Erabiltzaile
adminUserSettings.addUser=Erabiltzaile berria adminUserSettings.addUser=Erabiltzaile berria
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Rolak adminUserSettings.roles=Rolak
adminUserSettings.role=Rol adminUserSettings.role=Rol
@@ -332,6 +336,10 @@ home.certSign.title=Sinatu ziurtagiriarekin
home.certSign.desc=Sinatu PDF bat Ziurtagiri/Gako batekin (PEM/P12) home.certSign.desc=Sinatu PDF bat Ziurtagiri/Gako batekin (PEM/P12)
certSign.tags=authenticate,PEM,P12,official,encrypt certSign.tags=authenticate,PEM,P12,official,encrypt
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Zenbait orrialderen diseinua home.pageLayout.title=Zenbait orrialderen diseinua
home.pageLayout.desc=Elkartu orri bakar batean PDF dokumentu baten zenbait orrialde home.pageLayout.desc=Elkartu orri bakar batean PDF dokumentu baten zenbait orrialde
pageLayout.tags=merge,composite,single-view,organize pageLayout.tags=merge,composite,single-view,organize
@@ -655,6 +663,13 @@ certSign.name=Izena
certSign.submit=Sinatu PDFa certSign.submit=Sinatu PDFa
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Ezabatu zuriuneak removeBlanks.title=Ezabatu zuriuneak
removeBlanks.header=Ezabatu orrialde zuriak removeBlanks.header=Ezabatu orrialde zuriak
@@ -788,6 +803,7 @@ merge.title=Elkartu
merge.header=Elkartu zenbait PDF (2+) merge.header=Elkartu zenbait PDF (2+)
merge.sortByName=Sort by nameOrdenatu izenaren arabera merge.sortByName=Sort by nameOrdenatu izenaren arabera
merge.sortByDate=Ordenatu dataren arabera merge.sortByDate=Ordenatu dataren arabera
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Elkartu merge.submit=Elkartu
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
pdfToPDFA.submit=Bihurtu pdfToPDFA.submit=Bihurtu
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=License
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=Utilisateur non trouvé.
incorrectPasswordMessage=Le mot de passe actuel est incorrect. incorrectPasswordMessage=Le mot de passe actuel est incorrect.
usernameExistsMessage=Le nouveau nom dutilisateur existe déjà. usernameExistsMessage=Le nouveau nom dutilisateur existe déjà.
invalidUsernameMessage=Nom dutilisateur invalide, le nom dutilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide. invalidUsernameMessage=Nom dutilisateur invalide, le nom dutilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Impossible de supprimer lutilisateur actuellement connecté. deleteCurrentUserMessage=Impossible de supprimer lutilisateur actuellement connecté.
deleteUsernameExistsMessage=Le nom dutilisateur nexiste pas et ne peut pas être supprimé. deleteUsernameExistsMessage=Le nom dutilisateur nexiste pas et ne peut pas être supprimé.
downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel. downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel.
@@ -85,6 +86,7 @@ pipeline.defaultOption=Personnaliser
pipeline.submitButton=Soumettre pipeline.submitButton=Soumettre
pipeline.help=Aide Pipeline pipeline.help=Aide Pipeline
pipeline.scanHelp=Aide analyse de dossier pipeline.scanHelp=Aide analyse de dossier
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Administration des paramètres des utilisateurs
adminUserSettings.admin=Administateur adminUserSettings.admin=Administateur
adminUserSettings.user=Utilisateur adminUserSettings.user=Utilisateur
adminUserSettings.addUser=Ajouter un utilisateur adminUserSettings.addUser=Ajouter un utilisateur
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Le nom d'utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide. adminUserSettings.usernameInfo=Le nom d'utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
adminUserSettings.roles=Rôles adminUserSettings.roles=Rôles
adminUserSettings.role=Rôle adminUserSettings.role=Rôle
@@ -267,7 +271,7 @@ home.fileToPDF.desc=Convertissez presque nimporte quel fichiers en PDF (DOCX,
fileToPDF.tags=convertion,transformation,format,document,image,slide,texte,conversion,office,docs,word,excel,powerpoint fileToPDF.tags=convertion,transformation,format,document,image,slide,texte,conversion,office,docs,word,excel,powerpoint
home.ocr.title=OCR / Nettoyage des numérisations home.ocr.title=OCR / Nettoyage des numérisations
home.ocr.desc=Utilisez lOCR pour analyser et détecter le texte des images dun PDF et le rajouter en temps que tel. home.ocr.desc=Utilisez lOCR pour analyser et détecter le texte des images dun PDF et le rajouter en tant que tel.
ocr.tags=ocr,reconnaissance,texte,image,numérisation,scan,read,identify,detection,editable ocr.tags=ocr,reconnaissance,texte,image,numérisation,scan,read,identify,detection,editable
@@ -332,6 +336,10 @@ home.certSign.title=Signer avec un certificat
home.certSign.desc=Signez un PDF avec un certificat ou une clé (PEM/P12). home.certSign.desc=Signez un PDF avec un certificat ou une clé (PEM/P12).
certSign.tags=signer,chiffrer,certificat,authenticate,PEM,P12,official,encrypt certSign.tags=signer,chiffrer,certificat,authenticate,PEM,P12,official,encrypt
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Fusionner des pages home.pageLayout.title=Fusionner des pages
home.pageLayout.desc=Fusionnez plusieurs pages dun PDF en une seule. home.pageLayout.desc=Fusionnez plusieurs pages dun PDF en une seule.
pageLayout.tags=fusionner,merge,composite,single-view,organize pageLayout.tags=fusionner,merge,composite,single-view,organize
@@ -452,12 +460,12 @@ login.locked=Votre compte a été verrouillé.
login.signinTitle=Veuillez vous connecter login.signinTitle=Veuillez vous connecter
login.ssoSignIn=Se connecter via l'authentification unique login.ssoSignIn=Se connecter via l'authentification unique
login.oauth2AutoCreateDisabled=OAUTH2 Création automatique d'utilisateur désactivée login.oauth2AutoCreateDisabled=OAUTH2 Création automatique d'utilisateur désactivée
login.oauth2RequestNotFound=Authorization request not found login.oauth2RequestNotFound=Demande d'autorisation introuvable
login.oauth2InvalidUserInfoResponse=Invalid User Info Response login.oauth2InvalidUserInfoResponse=Réponse contenant les informations de l'utilisateur est invalide
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Requête invalide
login.oauth2AccessDenied=Access Denied login.oauth2AccessDenied=Accès refusé
login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidTokenResponse=Réponse contenant le jeton est invalide
login.oauth2InvalidIdToken=Invalid Id Token login.oauth2InvalidIdToken=Jeton d'identification invalide
#auto-redact #auto-redact
@@ -655,6 +663,13 @@ certSign.name=Nom
certSign.submit=Signer certSign.submit=Signer
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Supprimer les pages vierges removeBlanks.title=Supprimer les pages vierges
removeBlanks.header=Supprimer les pages vierges removeBlanks.header=Supprimer les pages vierges
@@ -679,14 +694,14 @@ compare.document.2=Document 2
compare.submit=Comparer compare.submit=Comparer
#BookToPDF #BookToPDF
BookToPDF.title=Books and Comics to PDF BookToPDF.title=Livres et BD vers PDF
BookToPDF.header=Book to PDF BookToPDF.header=Livre vers PDF
BookToPDF.credit=Utiliser Calibre BookToPDF.credit=Utiliser Calibre
BookToPDF.submit=Convertir BookToPDF.submit=Convertir
#PDFToBook #PDFToBook
PDFToBook.title=PDF to Book PDFToBook.title=PDF vers Livre
PDFToBook.header=PDF to Book PDFToBook.header=PDF vers Livre
PDFToBook.selectText.1=Format PDFToBook.selectText.1=Format
PDFToBook.credit=Utiliser Calibre PDFToBook.credit=Utiliser Calibre
PDFToBook.submit=Convertir PDFToBook.submit=Convertir
@@ -788,6 +803,7 @@ merge.title=Fusionner
merge.header=Fusionner plusieurs PDF merge.header=Fusionner plusieurs PDF
merge.sortByName=Trier par nom merge.sortByName=Trier par nom
merge.sortByDate=Trier par date merge.sortByDate=Trier par date
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Fusionner merge.submit=Fusionner
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Ce service utilise OCRmyPDF pour la conversion en PDF/A.
pdfToPDFA.submit=Convertir pdfToPDFA.submit=Convertir
pdfToPDFA.tip=Ne fonctionne actuellement pas pour plusieurs entrées à la fois pdfToPDFA.tip=Ne fonctionne actuellement pas pour plusieurs entrées à la fois
pdfToPDFA.outputFormat=Format de sortie pdfToPDFA.outputFormat=Format de sortie
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=Licence licenses.license=Licence
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Désolé pour ce problème ! error.sorry=Désolé pour ce problème !

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=उपयोगकर्ता नहीं मिला।
incorrectPasswordMessage=वर्तमान पासवर्ड गलत है। incorrectPasswordMessage=वर्तमान पासवर्ड गलत है।
usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है। usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है।
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता downgradeCurrentUserMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=व्यवस्थापक उपयोगकर्
adminUserSettings.admin=व्यवस्थापक adminUserSettings.admin=व्यवस्थापक
adminUserSettings.user=उपयोगकर्ता adminUserSettings.user=उपयोगकर्ता
adminUserSettings.addUser=नया उपयोगकर्ता जोड़ें adminUserSettings.addUser=नया उपयोगकर्ता जोड़ें
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=रोल्स adminUserSettings.roles=रोल्स
adminUserSettings.role=रोल adminUserSettings.role=रोल
@@ -332,6 +336,10 @@ home.certSign.title=प्रमाणपत्र के साथ हस्त
home.certSign.desc=पीडीएफ़ को प्रमाणपत्र/कुंजी (PEM/P12) के साथ हस्ताक्षरित करता है। home.certSign.desc=पीडीएफ़ को प्रमाणपत्र/कुंजी (PEM/P12) के साथ हस्ताक्षरित करता है।
certSign.tags=प्रमाणीकरण, PEM, P12, आधिकारिक, एन्क्रिप्ट certSign.tags=प्रमाणीकरण, PEM, P12, आधिकारिक, एन्क्रिप्ट
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=मल्टी-पेज लेआउट home.pageLayout.title=मल्टी-पेज लेआउट
home.pageLayout.desc=पीडीएफ़ दस्तावेज़ के कई पेजों को एक ही पेज में मर्ज करता है। home.pageLayout.desc=पीडीएफ़ दस्तावेज़ के कई पेजों को एक ही पेज में मर्ज करता है।
pageLayout.tags=मर्ज, संयोजित, एकल दृश्य, संगठित pageLayout.tags=मर्ज, संयोजित, एकल दृश्य, संगठित
@@ -655,6 +663,13 @@ certSign.name=नाम
certSign.submit=पीडीएफ़ पर हस्ताक्षर करें certSign.submit=पीडीएफ़ पर हस्ताक्षर करें
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=खाली पेज हटाएं removeBlanks.title=खाली पेज हटाएं
removeBlanks.header=खाली पेज हटाएं removeBlanks.header=खाली पेज हटाएं
@@ -788,6 +803,7 @@ merge.title=मर्ज
merge.header=एक से अधिक PDF एक साथ मर्ज करें (2+) merge.header=एक से अधिक PDF एक साथ मर्ज करें (2+)
merge.sortByName=नाम से क्रमबद्ध करें merge.sortByName=नाम से क्रमबद्ध करें
merge.sortByDate=तारीख से क्रमबद्ध करें merge.sortByDate=तारीख से क्रमबद्ध करें
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=मर्ज करें merge.submit=मर्ज करें
@@ -965,6 +981,7 @@ pdfToPDFA.credit=इस सेवा में PDF/A परिवर्तन
pdfToPDFA.submit=परिवर्तित करें pdfToPDFA.submit=परिवर्तित करें
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=License
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!

File diff suppressed because it is too large Load Diff

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=A felhasználó nem található.
incorrectPasswordMessage=A jelenlegi jelszó helytelen. incorrectPasswordMessage=A jelenlegi jelszó helytelen.
usernameExistsMessage=Az új felhasználónév már létezik. usernameExistsMessage=Az új felhasználónév már létezik.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=A jelenlegi felhasználó szerepkörét nem lehet visszaminősíteni downgradeCurrentUserMessage=A jelenlegi felhasználó szerepkörét nem lehet visszaminősíteni
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Adminisztrátori Felhasználói Vezérlési Beállítá
adminUserSettings.admin=Adminisztrátor adminUserSettings.admin=Adminisztrátor
adminUserSettings.user=Felhasználó adminUserSettings.user=Felhasználó
adminUserSettings.addUser=Új felhasználó hozzáadása adminUserSettings.addUser=Új felhasználó hozzáadása
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Szerepek adminUserSettings.roles=Szerepek
adminUserSettings.role=Szerep adminUserSettings.role=Szerep
@@ -332,6 +336,10 @@ home.certSign.title=Aláírás Tanúsítvánnyal
home.certSign.desc=PDF aláírása tanúsítvánnyal/kulccsal (PEM/P12) home.certSign.desc=PDF aláírása tanúsítvánnyal/kulccsal (PEM/P12)
certSign.tags=hitelesítés,PEM,P12,hivatalos,segitít,álca certSign.tags=hitelesítés,PEM,P12,hivatalos,segitít,álca
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Több oldal elrendezése home.pageLayout.title=Több oldal elrendezése
home.pageLayout.desc=Több oldal egyesítése egy PDF dokumentumban egyetlen oldallá home.pageLayout.desc=Több oldal egyesítése egy PDF dokumentumban egyetlen oldallá
pageLayout.tags=egyesítés,kompozit,egy oldal,megszervez pageLayout.tags=egyesítés,kompozit,egy oldal,megszervez
@@ -655,6 +663,13 @@ certSign.name=Név
certSign.submit=PDF aláírása certSign.submit=PDF aláírása
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Üres oldalak eltávolítása removeBlanks.title=Üres oldalak eltávolítása
removeBlanks.header=Üres oldalak eltávolítása removeBlanks.header=Üres oldalak eltávolítása
@@ -788,6 +803,7 @@ merge.title=Összevonás
merge.header=Több PDF összevonása (2+) merge.header=Több PDF összevonása (2+)
merge.sortByName=Név szerinti rendezés merge.sortByName=Név szerinti rendezés
merge.sortByDate=Dátum szerinti rendezés merge.sortByDate=Dátum szerinti rendezés
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Összevonás merge.submit=Összevonás
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Ez a szolgáltatás az OCRmyPDF-t használja a PDF/A konverzió
pdfToPDFA.submit=Konvertálás pdfToPDFA.submit=Konvertálás
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=License
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!

View File

@@ -55,6 +55,7 @@ userNotFoundMessage=Pengguna tidak ditemukan.
incorrectPasswordMessage=Kata sandi saat ini salah. incorrectPasswordMessage=Kata sandi saat ini salah.
usernameExistsMessage=Nama pengguna baru sudah ada. usernameExistsMessage=Nama pengguna baru sudah ada.
invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
confirmPasswordErrorMessage=New Password and Confirm New Password must match.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Tidak dapat menurunkan peran pengguna saat ini downgradeCurrentUserMessage=Tidak dapat menurunkan peran pengguna saat ini
@@ -85,6 +86,7 @@ pipeline.defaultOption=Custom
pipeline.submitButton=Submit pipeline.submitButton=Submit
pipeline.help=Pipeline Help pipeline.help=Pipeline Help
pipeline.scanHelp=Folder Scanning Help pipeline.scanHelp=Folder Scanning Help
pipeline.deletePrompt=Are you sure you want to delete pipeline
###################### ######################
# Pipeline Options # # Pipeline Options #
@@ -173,6 +175,8 @@ adminUserSettings.header=Pengaturan Kontrol Admin
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Pengguna adminUserSettings.user=Pengguna
adminUserSettings.addUser=Tambahkan Pengguna Baru adminUserSettings.addUser=Tambahkan Pengguna Baru
adminUserSettings.deleteUser=Delete User
adminUserSettings.confirmDeleteUser=Should the user be deleted?
adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Peran adminUserSettings.roles=Peran
adminUserSettings.role=Peran adminUserSettings.role=Peran
@@ -332,6 +336,10 @@ home.certSign.title=Tanda tangani dengan Sertifikat
home.certSign.desc=Menandatangani PDF dengan Certificate/Key (PEM/P12) home.certSign.desc=Menandatangani PDF dengan Certificate/Key (PEM/P12)
certSign.tags=mengotentikasi, PEM, P12, resmi, mengenkripsi certSign.tags=mengotentikasi, PEM, P12, resmi, mengenkripsi
home.removeCertSign.title=Remove Certificate Sign
home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Tata Letak Multi-Halaman home.pageLayout.title=Tata Letak Multi-Halaman
home.pageLayout.desc=Menggabungkan beberapa halaman dokumen PDF menjadi satu halaman home.pageLayout.desc=Menggabungkan beberapa halaman dokumen PDF menjadi satu halaman
pageLayout.tags=menggabungkan, komposit, tampilan tunggal, mengatur pageLayout.tags=menggabungkan, komposit, tampilan tunggal, mengatur
@@ -655,6 +663,13 @@ certSign.name=Nama
certSign.submit=Tanda tangani PDF certSign.submit=Tanda tangani PDF
#removeCertSign
removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks
removeBlanks.title=Hapus Halaman Kosong removeBlanks.title=Hapus Halaman Kosong
removeBlanks.header=Remove Blank Pages removeBlanks.header=Remove Blank Pages
@@ -788,6 +803,7 @@ merge.title=Gabungkan
merge.header=Gabungkan beberapa PDFs (2+) merge.header=Gabungkan beberapa PDFs (2+)
merge.sortByName=Sortir berdasarkan nama merge.sortByName=Sortir berdasarkan nama
merge.sortByDate=Sortir berdasrkan tanggal merge.sortByDate=Sortir berdasrkan tanggal
merge.removeCertSign=Remove digital signature in the merged file?
merge.submit=Gabungkan merge.submit=Gabungkan
@@ -965,6 +981,7 @@ pdfToPDFA.credit=Layanan ini menggunakan OCRmyPDF untuk konversi PDF/A.
pdfToPDFA.submit=Konversi pdfToPDFA.submit=Konversi
pdfToPDFA.tip=Currently does not work for multiple inputs at once pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Output format pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1065,6 +1082,15 @@ licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=License
#survey
survey.nav=Survey
survey.title=Stirling-PDF Survey
survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF!
survey.please=Please consider taking our survey!
survey.disabled=(Survey popup will be disabled in following updates but available at foot of page)
survey.button=Take Survey
survey.dontShowAgain=Don't show again
#error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!

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