2025-01-30 18:55:33 +00:00
|
|
|
<th:block th:fragment="navElements">
|
2025-02-06 10:38:14 +00:00
|
|
|
<div id="groupOrganize" class="feature-group">
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.organize})}">
|
|
|
|
</div>
|
|
|
|
<div class="nav-group-container">
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'organize')}">
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
2025-01-30 18:55:33 +00:00
|
|
|
|
2025-02-06 10:38:14 +00:00
|
|
|
<div
|
2025-01-30 18:55:33 +00:00
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'add_to_photos', 'home.merge.title', 'home.merge.desc', 'merge.tags', 'organize')}">
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdfs', 'cut', 'home.split.title', 'home.split.desc', 'split.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
2025-01-30 18:55:33 +00:00
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('rotate-pdf', 'rotate_right', 'home.rotate.title', 'home.rotate.desc', 'rotate.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('crop', 'crop', 'home.crop.title', 'home.crop.desc', 'crop.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-organizer', 'format_list_bulleted', 'home.pdfOrganiser.title', 'home.pdfOrganiser.desc', 'pdfOrganiser.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-pages', 'delete', 'home.removePages.title', 'home.removePages.desc', 'removePages.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('multi-page-layout', 'dashboard', 'home.pageLayout.title', 'home.pageLayout.desc', 'pageLayout.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('scale-pages', 'fullscreen', 'home.scalePages.title', 'home.scalePages.desc', 'scalePages.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('extract-page', 'upload', 'home.extractPage.title', 'home.extractPage.desc', 'extractPage.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-single-page', 'looks_one', 'home.PdfToSinglePage.title', 'home.PdfToSinglePage.desc', 'PdfToSinglePage.tags', 'organize')}">
|
|
|
|
</div>
|
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
2025-01-30 18:55:33 +00:00
|
|
|
|
2025-02-06 10:38:14 +00:00
|
|
|
<div id="groupConvertTo" class="feature-group">
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertTo})}">
|
|
|
|
</div>
|
|
|
|
<div class="nav-group-container">
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('img-to-pdf', 'picture_as_pdf', 'home.imageToPdf.title', 'home.imageToPdf.desc', 'imageToPdf.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('file-to-pdf', 'draft', 'home.fileToPDF.title', 'home.fileToPDF.desc', 'fileToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('url-to-pdf', 'link', 'home.URLToPDF.title', 'home.URLToPDF.desc', 'URLToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('html-to-pdf', 'html', 'home.HTMLToPDF.title', 'home.HTMLToPDF.desc', 'HTMLToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('markdown-to-pdf', 'markdown', 'home.MarkdownToPDF.title', 'home.MarkdownToPDF.desc', 'MarkdownToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
Add EML to PDF conversion functionality (#3650)
This pull request introduces a new feature for converting EML (email)
files to PDF format, along with various customization options. It
includes backend support for the conversion process, frontend
integration for user interaction, and updates to localization and
navigation.
### Backend Changes:
* **Added EML to PDF Conversion Logic**: Implemented a new controller
`ConvertEmlToPDF` with an endpoint `/api/v1/convert/eml/pdf` to handle
EML-to-PDF conversion requests. This includes validation, support for
HTML intermediate files, and enhanced options such as attachment
handling and size limits.
(`src/main/java/stirling/software/SPDF/controller/api/converters/ConvertEmlToPDF.java`)
* **New Model for Conversion Requests**: Introduced `EmlToPdfRequest`
class to encapsulate request parameters like attachment inclusion,
maximum attachment size, and HTML download options.
(`common/src/main/java/stirling/software/common/model/api/converters/EmlToPdfRequest.java`)
* **Dependency Update**: Added `jakarta.mail:jakarta.mail-api:2.1.3` to
the project dependencies for handling EML files. (`common/build.gradle`)

### Frontend Changes:
* **New Web Form**: Created a new HTML page `eml-to-pdf.html` for the
EML-to-PDF conversion tool, allowing users to upload EML files and
configure options.
(`src/main/resources/templates/convert/eml-to-pdf.html`)
* **Navigation Update**: Added a navigation entry for the EML-to-PDF
tool in the sidebar.
(`src/main/resources/templates/fragments/navElements.html`)

### Localization and UI Enhancements:
* **Localization Strings**: Added support for the EML-to-PDF tool in the
`messages_en_GB.properties` file, including titles, descriptions, and
help texts. (`src/main/resources/messages_en_GB.properties`)
* **Web Controller Update**: Added a new route `/eml-to-pdf` in
`ConverterWebController` to serve the EML-to-PDF form.
(`src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java`)
### Highlights:
* Attachment support: and Attachment section is created with fully
working PDFAnnotations, which enable users to click paperclip and
redirects to the attachment. (Requires PDF.js)
* If attachments are present creates a catalog of attachments
* Encoding support inside the body and header for local charachters e.g:
ö,ő,ü etc..
* Optional: Users can download HTMLs, aswell as PDFs
* Advanced features for conversion that: keep links, keep as much
formatting as possible, keep images incl relative sizes, popular fonts
and many more.
### Known limitations
* Generally EML-to-HTML is very reliable however emails with complicated
layout cause problem for Weasyprint, so not all emails can reliably
converted to PDF.
* Users need PDF.js and PDFCatalog support for best attachment/embedding
support (but is not strict requirement)
### Challanges
* Embedding was a large headache, not the Embedding itself per se more
so the additional niceties such as: links, the catalog, consistent
symbols (replaced the paperclip that is generated by pdf viewer with
emoji paperclip that is consistent for everybody) and it was generally
prone all sorts of hard to diagnose issues.
* Encoding issues
* Formatting issues
However I think addressed these so shouldn't cause any additional
headache. :)
### Examples:




Closes #503
---
## Checklist
### General
- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [x] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-08 22:26:01 +02:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('eml-to-pdf', 'email', 'home.EMLToPDF.title', 'home.EMLToPDF.desc', 'EMLToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
2025-01-30 18:55:33 +00:00
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
|
|
|
<div id="groupConvertFrom" class="feature-group">
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertFrom})}">
|
|
|
|
</div>
|
|
|
|
<div class="nav-group-container">
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-img', 'photo_library', 'home.pdfToImage.title', 'home.pdfToImage.desc', 'pdfToImage.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-pdfa', 'picture_as_pdf', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc', 'pdfToPDFA.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-word', 'description', 'home.PDFToWord.title', 'home.PDFToWord.desc', 'PDFToWord.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-presentation', 'slideshow', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc', 'PDFToPresentation.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-text', 'text_fields', 'home.PDFToText.title', 'home.PDFToText.desc', 'PDFToText.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-html', 'html', 'home.PDFToHTML.title', 'home.PDFToHTML.desc', 'PDFToHTML.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-xml', 'code', 'home.PDFToXML.title', 'home.PDFToXML.desc', 'PDFToXML.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-csv', 'csv', 'home.tableExtraxt.title', 'home.tableExtraxt.desc', 'tableExtraxt.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
2025-02-06 10:38:14 +00:00
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-markdown', 'markdown_copy', 'home.PDFToMarkdown.title', 'home.PDFToMarkdown.desc', 'PDFToMarkdown.tags', 'convert')}">
|
|
|
|
</div>
|
2025-01-30 18:55:33 +00:00
|
|
|
|
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
|
|
|
<div id="convertGroup" class="feature-group">
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertTo})}">
|
2025-01-30 18:55:33 +00:00
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
<div class="nav-group-container">
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('img-to-pdf', 'picture_as_pdf', 'home.imageToPdf.title', 'home.imageToPdf.desc', 'imageToPdf.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('file-to-pdf', 'draft', 'home.fileToPDF.title', 'home.fileToPDF.desc', 'fileToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('url-to-pdf', 'link', 'home.URLToPDF.title', 'home.URLToPDF.desc', 'URLToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('html-to-pdf', 'html', 'home.HTMLToPDF.title', 'home.HTMLToPDF.desc', 'HTMLToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('markdown-to-pdf', 'markdown', 'home.MarkdownToPDF.title', 'home.MarkdownToPDF.desc', 'MarkdownToPDF.tags', 'convertto')}">
|
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertFrom})}">
|
|
|
|
</div>
|
|
|
|
<div class="nav-group-container">
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-img', 'photo_library', 'home.pdfToImage.title', 'home.pdfToImage.desc', 'pdfToImage.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-pdfa', 'picture_as_pdf', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc', 'pdfToPDFA.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-word', 'description', 'home.PDFToWord.title', 'home.PDFToWord.desc', 'PDFToWord.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-presentation', 'slideshow', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc', 'PDFToPresentation.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-text', 'text_fields', 'home.PDFToText.title', 'home.PDFToText.desc', 'PDFToText.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-html', 'html', 'home.PDFToHTML.title', 'home.PDFToHTML.desc', 'PDFToHTML.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-xml', 'code', 'home.PDFToXML.title', 'home.PDFToXML.desc', 'PDFToXML.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-csv', 'csv', 'home.tableExtraxt.title', 'home.tableExtraxt.desc', 'tableExtraxt.tags', 'convert')}">
|
|
|
|
</div>
|
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
|
|
|
<div id="groupSecurity" class="feature-group">
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.security})}">
|
2025-01-30 18:55:33 +00:00
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
<div class="nav-group-container">
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('add-password', 'lock', 'home.addPassword.title', 'home.addPassword.desc', 'addPassword.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-password', 'lock_open_right', 'home.removePassword.title', 'home.removePassword.desc', 'removePassword.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('change-permissions', 'encrypted', 'home.permissions.title', 'home.permissions.desc', 'permissions.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('sign', 'signature', 'home.sign.title', 'home.sign.desc', 'sign.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('cert-sign', 'workspace_premium', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div
|
2025-02-06 10:38:14 +00:00
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('validate-signature', 'verified', 'home.validateSignature.title', 'home.validateSignature.desc', 'validateSignature.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-cert-sign', 'remove_moderator', 'home.removeCertSign.title', 'home.removeCertSign.desc', 'removeCertSign.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('sanitize-pdf', 'sanitizer', 'home.sanitizePdf.title', 'home.sanitizePdf.desc', 'sanitizePdf.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('auto-redact', '/images/redact-auto.svg#icon-redact-auto', 'home.autoRedact.title', 'home.autoRedact.desc', 'autoRedact.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('redact', '/images/redact-manual.svg#icon-redact-manual', 'home.redact.title', 'home.redact.desc', 'redact.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('stamp', 'approval', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags', 'security')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('add-watermark', 'water_drop', 'home.watermark.title', 'home.watermark.desc', 'watermark.tags', 'security')}">
|
2025-01-30 18:55:33 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
2025-01-30 18:55:33 +00:00
|
|
|
|
2025-02-06 10:38:14 +00:00
|
|
|
<div id="groupView" class="feature-group">
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.edit})}">
|
|
|
|
</div>
|
|
|
|
<div class="nav-group-container">
|
|
|
|
<div
|
2025-01-30 18:55:33 +00:00
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('view-pdf', 'menu_book', 'home.viewPdf.title', 'home.viewPdf.desc', 'viewPdf.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('add-page-numbers', '123', 'home.add-page-numbers.title', 'home.add-page-numbers.desc', 'add-page-numbers.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('add-image', 'text_fields', 'home.addImage.title', 'home.addImage.desc', 'addImage.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('change-metadata', 'assignment', 'home.changeMetadata.title', 'home.changeMetadata.desc', 'changeMetadata.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('ocr-pdf', 'quick_reference_all', 'home.ocr.title', 'home.ocr.desc', 'ocr.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('extract-images', 'photo_library', 'home.extractImages.title', 'home.extractImages.desc', 'extractImages.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('flatten', 'layers_clear', 'home.flatten.title', 'home.flatten.desc', 'flatten.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-blanks', 'scan_delete', 'home.removeBlanks.title', 'home.removeBlanks.desc', 'removeBlanks.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-annotations', 'thread_unread', 'home.removeAnnotations.title', 'home.removeAnnotations.desc', 'removeAnnotations.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('compare', 'compare', 'home.compare.title', 'home.compare.desc', 'compare.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('get-info-on-pdf', 'info', 'home.getPdfInfo.title', 'home.getPdfInfo.desc', 'getPdfInfo.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-image-pdf', 'remove_selection', 'home.removeImagePdf.title', 'home.removeImagePdf.desc', 'removeImagePdf.tags', 'other')}">
|
|
|
|
</div>
|
|
|
|
<div
|
2025-02-06 10:38:14 +00:00
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('replace-and-invert-color-pdf', 'format_color_fill', 'home.replaceColorPdf.title', 'home.replaceColorPdf.desc', 'replaceColorPdf.tags', 'other')}">
|
2025-01-30 18:55:33 +00:00
|
|
|
</div>
|
2025-04-29 11:40:08 +01:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('unlock-pdf-forms', 'preview_off', 'home.unlockPDFForms.title', 'home.unlockPDFForms.desc', 'unlockPDFForms.tags', 'other')}">
|
|
|
|
</div>
|
2025-01-30 18:55:33 +00:00
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
|
|
|
<div id="groupAdvanced" class="feature-group">
|
|
|
|
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.advance})}">
|
|
|
|
</div>
|
|
|
|
<div class="nav-group-container">
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('pipeline', 'family_history', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('adjust-contrast', 'palette', 'home.adjust-contrast.title', 'home.adjust-contrast.desc', 'adjust-contrast.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('compress-pdf', 'zoom_in_map', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('extract-image-scans', 'scanner', 'home.ScannerImageSplit.title', 'home.ScannerImageSplit.desc', 'ScannerImageSplit.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('repair', 'build', 'home.repair.title', 'home.repair.desc', 'repair.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('auto-rename', '/images/rename.svg#icon-rename', 'home.auto-rename.title', 'home.auto-rename.desc', 'auto-rename.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('auto-split-pdf', '/images/split-auto.svg#icon-split-auto', 'home.autoSplitPDF.title', 'home.autoSplitPDF.desc', 'autoSplitPDF.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('show-javascript', 'javascript', 'home.showJS.title', 'home.showJS.desc', 'showJS.tags', 'advance')}">
|
|
|
|
</div>
|
Added scan filter feature (#3530)
# Description of Changes
Please provide a summary of the changes, including:
This pull request introduces the "Fake Scan" feature, which simulates
scanned PDFs with customizable settings. The changes include the removal
of a work-in-progress controller, the addition of a new request model,
and updates to the frontend to support the feature.
### Backend Changes:
* **Removed the unfinished `FakeScanControllerWIP`:** The entire
`FakeScanControllerWIP` class, which contained unimplemented and
experimental code for processing PDFs, has been removed. This cleanup
eliminates unused code and dependencies. Some of the original code of
removed file was ported to the new Controller.
* **Added `FakeScanRequest` model:** Introduced a new model class
`FakeScanRequest` to handle input parameters for the "Fake Scan"
feature. It includes fields for file input, quality, rotation,
colorspace, and other advanced settings, with validation and default
values.
### Frontend Changes:
* **Localization updates for the "Fake Scan" feature:** Added new
localization keys for the "Fake Scan" feature, including titles,
descriptions, and advanced settings options like quality, rotation, and
colorspace.
* **Added "Fake Scan" card to the homepage
### Pictures:
Front-end

Example document (based on defaults; can be drastically changed
according to need.):

### Quirks/known issues
- Performance: It might take even reasonable hardware to convert bigger
pdf >500KB more than a few minutes.
- Yellowish filter applies to the whole document and also incl to the
background. (not desirable in some instances)
- There is some randomness involved in the default preset, helps imitate
scan but some user might find it annoying. (but it can be disabled
through advanced settings).
- Some features might confusing to people with no additional context.
Closes #458
---
## Checklist
### General
- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
2025-05-31 17:26:52 +02:00
|
|
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry('fake-scan', 'scanner', 'fakeScan.title', 'fakeScan.description', 'fakeScan.tags', 'advance')}"></div>
|
2025-01-30 18:55:33 +00:00
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('split-by-size-or-count', '/images/split-size.svg#icon-split-size', 'home.autoSizeSplitPDF.title', 'home.autoSizeSplitPDF.desc', 'autoSizeSplitPDF.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('overlay-pdf', 'layers', 'home.overlay-pdfs.title', 'home.overlay-pdfs.desc', 'overlay-pdfs.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntry :: navbarEntry('split-pdf-by-sections', 'grid_on', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags', 'advance')}">
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('split-pdf-by-chapters', '/images/split-chapters.svg#icon-split-chapters', 'home.splitPdfByChapters.title', 'home.splitPdfByChapters.desc', 'splitPdfByChapters.tags', 'advance')}">
|
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</div>
|
2025-01-30 18:55:33 +00:00
|
|
|
</div>
|
2025-02-06 10:38:14 +00:00
|
|
|
</th:block>
|