wip - fixing embed feature

This commit is contained in:
DarioGii 2025-06-13 14:59:54 +01:00
parent 0f5c549fb4
commit a0b176b076
10 changed files with 43 additions and 28 deletions

View File

@ -173,6 +173,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Other", "get-info-on-pdf"); addEndpointToGroup("Other", "get-info-on-pdf");
addEndpointToGroup("Other", "show-javascript"); addEndpointToGroup("Other", "show-javascript");
addEndpointToGroup("Other", "remove-image-pdf"); addEndpointToGroup("Other", "remove-image-pdf");
addEndpointToGroup("Other", "add-attachments");
// CLI // CLI
addEndpointToGroup("CLI", "compress-pdf"); addEndpointToGroup("CLI", "compress-pdf");
@ -251,6 +252,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "pdf-to-text"); addEndpointToGroup("Java", "pdf-to-text");
addEndpointToGroup("Java", "remove-image-pdf"); addEndpointToGroup("Java", "remove-image-pdf");
addEndpointToGroup("Java", "pdf-to-markdown"); addEndpointToGroup("Java", "pdf-to-markdown");
addEndpointToGroup("Java", "add-attachments");
// Javascript // Javascript
addEndpointToGroup("Javascript", "pdf-organizer"); addEndpointToGroup("Javascript", "pdf-organizer");

View File

@ -3,10 +3,7 @@ package stirling.software.SPDF.controller.api.misc;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.PageMode;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -33,6 +30,7 @@ public class AttachmentsController {
private final PDFAttachmentServiceInterface pdfAttachmentService; private final PDFAttachmentServiceInterface pdfAttachmentService;
@SuppressWarnings("DataFlowIssue")
@PostMapping(consumes = "multipart/form-data", value = "/add-attachments") @PostMapping(consumes = "multipart/form-data", value = "/add-attachments")
@Operation( @Operation(
summary = "Add attachments to PDF", summary = "Add attachments to PDF",
@ -50,15 +48,19 @@ public class AttachmentsController {
PDDocumentCatalog catalog = document.getDocumentCatalog(); PDDocumentCatalog catalog = document.getDocumentCatalog();
// Create embedded files name tree if it doesn't exist // Create embedded files name tree if it doesn't exist
PDEmbeddedFilesNameTreeNode efTree = catalog.getNames().getEmbeddedFiles(); PDDocumentNameDictionary documentNames = catalog.getNames();
PDEmbeddedFilesNameTreeNode embeddedFilesTree = new PDEmbeddedFilesNameTreeNode();
if (efTree == null) { if (documentNames != null) {
efTree = new PDEmbeddedFilesNameTreeNode(); embeddedFilesTree = documentNames.getEmbeddedFiles();
catalog.getNames().setEmbeddedFiles(efTree); } else {
documentNames = new PDDocumentNameDictionary(catalog);
documentNames.setEmbeddedFiles(embeddedFilesTree);
} }
// Add attachments // Add attachments
pdfAttachmentService.addAttachment(document, efTree, attachments); catalog.setNames(documentNames);
pdfAttachmentService.addAttachment(document, embeddedFilesTree, attachments);
// Set PageMode to UseAttachments to show the attachments panel // Set PageMode to UseAttachments to show the attachments panel
catalog.setPageMode(PageMode.USE_ATTACHMENTS); catalog.setPageMode(PageMode.USE_ATTACHMENTS);
@ -79,10 +81,8 @@ public class AttachmentsController {
public ResponseEntity<byte[]> removeAttachments( public ResponseEntity<byte[]> removeAttachments(
@RequestParam("fileInput") MultipartFile pdfFile) throws IOException { @RequestParam("fileInput") MultipartFile pdfFile) throws IOException {
// Load the PDF document // Load the PDF document and document catalog
PDDocument document = pdfDocumentFactory.load(pdfFile, true); PDDocument document = pdfDocumentFactory.load(pdfFile, true);
// Get the document catalog
PDDocumentCatalog catalog = document.getDocumentCatalog(); PDDocumentCatalog catalog = document.getDocumentCatalog();
// Remove embedded files // Remove embedded files

View File

@ -192,10 +192,10 @@ public class OtherWebController {
return "misc/auto-rename"; return "misc/auto-rename";
} }
@GetMapping("/attachments") @GetMapping("/add-attachments")
@Hidden @Hidden
public String attachmentsForm(Model model) { public String attachmentsForm(Model model) {
model.addAttribute("currentPage", "attachments"); model.addAttribute("currentPage", "attachments");
return "misc/attachments"; return "misc/add-attachments";
} }
} }

View File

@ -22,18 +22,28 @@ public class PDFAttachmentService implements PDFAttachmentServiceInterface {
@Override @Override
public void addAttachment( public void addAttachment(
PDDocument document, PDDocument document,
PDEmbeddedFilesNameTreeNode efTree, PDEmbeddedFilesNameTreeNode embeddedFilesTree,
List<MultipartFile> attachments) List<MultipartFile> attachments)
throws IOException { throws IOException {
// Get existing names or create new map // todo: sanitize attachments first
Map<String, PDComplexFileSpecification> existingNames = new java.util.HashMap<>(); // todo: find out how to access the embedded files in the PDF
Map<String, PDComplexFileSpecification> existingNames;
try { try {
existingNames = efTree.getNames(); existingNames = embeddedFilesTree.getNames();
if (existingNames == null) {
log.info("No existing embedded files found, creating new names map.");
// Initialize an empty map if no existing names are found
existingNames = new java.util.HashMap<>();
}
log.debug("Existing embedded files: {}", existingNames.keySet());
} catch (IOException e) { } catch (IOException e) {
log.warn("Could not retrieve existing embedded files, starting with empty map", e); log.error("Could not retrieve existing embedded files", e);
throw e;
} }
Map<String, PDComplexFileSpecification> finalExistingNames = existingNames; final Map<String, PDComplexFileSpecification> existingEmbeddedFiles = existingNames;
attachments.forEach( attachments.forEach(
attachment -> { attachment -> {
// Create attachments specification // Create attachments specification
@ -43,7 +53,6 @@ public class PDFAttachmentService implements PDFAttachmentServiceInterface {
"Embedded attachment: " + attachment.getOriginalFilename()); "Embedded attachment: " + attachment.getOriginalFilename());
try { try {
// Create embedded attachment
PDEmbeddedFile embeddedFile = PDEmbeddedFile embeddedFile =
new PDEmbeddedFile( new PDEmbeddedFile(
document, new ByteArrayInputStream(attachment.getBytes())); document, new ByteArrayInputStream(attachment.getBytes()));
@ -61,21 +70,20 @@ public class PDFAttachmentService implements PDFAttachmentServiceInterface {
fileSpecification.setEmbeddedFile(embeddedFile); fileSpecification.setEmbeddedFile(embeddedFile);
// Add to the existing names map // Add to the existing names map
finalExistingNames.put(attachment.getOriginalFilename(), fileSpecification); existingEmbeddedFiles.put(attachment.getOriginalFilename(), fileSpecification);
log.info( log.info(
"Added embedded attachment: {} ({} bytes)", "Added attachment: {} ({} bytes)",
attachment.getOriginalFilename(), attachment.getOriginalFilename(),
attachment.getSize()); attachment.getSize());
} catch (IOException e) { } catch (IOException e) {
log.error( log.warn(
"Failed to create embedded file for attachment: {}", "Failed to create embedded file for attachment: {}",
attachment.getOriginalFilename(), attachment.getOriginalFilename(),
e); e);
} }
}); });
// Update the name tree with all names embeddedFilesTree.setNames(existingNames);
efTree.setNames(existingNames);
} }
} }

View File

@ -238,7 +238,7 @@
th:replace="~{fragments/navbarEntry :: navbarEntry('unlock-pdf-forms', 'preview_off', 'home.unlockPDFForms.title', 'home.unlockPDFForms.desc', 'unlockPDFForms.tags', 'other')}"> th:replace="~{fragments/navbarEntry :: navbarEntry('unlock-pdf-forms', 'preview_off', 'home.unlockPDFForms.title', 'home.unlockPDFForms.desc', 'unlockPDFForms.tags', 'other')}">
</div> </div>
<div <div
th:replace="~{fragments/navbarEntry :: navbarEntry('attachments', 'attachment', 'home.attachments.title', 'home.attachments.desc', 'attachments.tags', 'other')}"> th:replace="~{fragments/navbarEntry :: navbarEntry('add-attachments', 'attachment', 'home.attachments.title', 'home.attachments.desc', 'attachments.tags', 'other')}">
</div> </div>
</div> </div>
</div> </div>

View File

@ -290,6 +290,9 @@
<div <div
th:replace="~{fragments/card :: card(id='unlock-pdf-forms', cardTitle=#{home.unlockPDFForms.title}, cardText=#{home.unlockPDFForms.desc}, cardLink='unlock-pdf-forms', toolIcon='preview_off', tags=#{unlockPDFForms.tags}, toolGroup='other')}"> th:replace="~{fragments/card :: card(id='unlock-pdf-forms', cardTitle=#{home.unlockPDFForms.title}, cardText=#{home.unlockPDFForms.desc}, cardLink='unlock-pdf-forms', toolIcon='preview_off', tags=#{unlockPDFForms.tags}, toolGroup='other')}">
</div> </div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry('add-attachments', 'attachment', 'home.attachments.title', 'home.attachments.desc', 'attachments.tags', 'other')}">
</div>
</div> </div>
</div> </div>

View File

@ -128,7 +128,7 @@ ui:
languages: [] # If empty, all languages are enabled. To display only German and Polish ["de_DE", "pl_PL"]. British English is always enabled. languages: [] # If empty, all languages are enabled. To display only German and Polish ["de_DE", "pl_PL"]. British English is always enabled.
endpoints: # All the possible endpoints are disabled endpoints: # All the possible endpoints are disabled
toRemove: [crop, merge-pdfs, multi-page-layout, overlay-pdfs, pdf-to-single-page, rearrange-pages, remove-image-pdf, remove-pages, rotate-pdf, scale-pages, split-by-size-or-count, split-pages, split-pdf-by-chapters, split-pdf-by-sections, add-password, add-watermark, auto-redact, cert-sign, get-info-on-pdf, redact, remove-cert-sign, remove-password, sanitize-pdf, validate-signature, file-to-pdf, html-to-pdf, img-to-pdf, markdown-to-pdf, pdf-to-csv, pdf-to-html, pdf-to-img, pdf-to-markdown, pdf-to-pdfa, pdf-to-presentation, pdf-to-text, pdf-to-word, pdf-to-xml, url-to-pdf, add-image, add-page-numbers, add-stamp, auto-rename, auto-split-pdf, compress-pdf, decompress-pdf, extract-image-scans, extract-images, flatten, ocr-pdf, remove-blanks, repair, replace-invert-pdf, show-javascript, update-metadata, filter-contains-image, filter-contains-text, filter-file-size, filter-page-count, filter-page-rotation, filter-page-size] # list endpoints to disable (e.g. ['img-to-pdf', 'remove-pages']) toRemove: [crop, merge-pdfs, multi-page-layout, overlay-pdfs, pdf-to-single-page, rearrange-pages, remove-image-pdf, remove-pages, rotate-pdf, scale-pages, split-by-size-or-count, split-pages, split-pdf-by-chapters, split-pdf-by-sections, add-password, add-watermark, auto-redact, cert-sign, get-info-on-pdf, redact, remove-cert-sign, remove-password, sanitize-pdf, validate-signature, file-to-pdf, html-to-pdf, img-to-pdf, markdown-to-pdf, pdf-to-csv, pdf-to-html, pdf-to-img, pdf-to-markdown, pdf-to-pdfa, pdf-to-presentation, pdf-to-text, pdf-to-word, pdf-to-xml, url-to-pdf, add-image, add-page-numbers, add-stamp, auto-rename, auto-split-pdf, compress-pdf, decompress-pdf, extract-image-scans, extract-images, flatten, ocr-pdf, remove-blanks, repair, replace-invert-pdf, show-javascript, update-metadata, filter-contains-image, filter-contains-text, filter-file-size, filter-page-count, filter-page-rotation, filter-page-size, add-attachments] # list endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
groupsToRemove: [] # list groups to disable (e.g. ['LibreOffice']) groupsToRemove: [] # list groups to disable (e.g. ['LibreOffice'])
metrics: metrics:

View File

@ -30,6 +30,7 @@
/api/v1/misc/add-stamp /api/v1/misc/add-stamp
/api/v1/misc/add-page-numbers /api/v1/misc/add-page-numbers
/api/v1/misc/add-image /api/v1/misc/add-image
/api/v1/misc/add-attachments
/api/v1/convert/url/pdf /api/v1/convert/url/pdf
/api/v1/convert/pdf/xml /api/v1/convert/pdf/xml
/api/v1/convert/pdf/word /api/v1/convert/pdf/word

View File

@ -51,3 +51,4 @@
/swagger-ui/index.html /swagger-ui/index.html
/licenses /licenses
/releases /releases
/add-attachments