From ef96f523e316ee0cbf6c0f8093aff79530b6bcea Mon Sep 17 00:00:00 2001 From: rehlert Date: Sat, 13 Jun 2026 13:32:55 +0200 Subject: [PATCH] The git changes introduce functionality to merge attachments from a processed ZIP archive into a single PDF file. Here is a summary of the changes: ### New Features - PDF Merging: Added the ability to merge multiple attachments (PDFs and images) from a processed ZIP archive into a single PDF document. - Image Conversion: Implemented automatic conversion of non-PNG images (like JPGs) to PNG format before embedding them into the merged PDF. ### File Changes - Dependencies: Added pdf-lib to the project's dependencies. - src/lib/zip-processing.ts: - Added mergeProcessedZipArchive to handle the core logic of creating a merged PDF. - Implemented helpers to embed PDF pages and convert/embed images. - Added toArrayBuffer and convertImageBytesToPng utilities for handling binary data and canvas-based image processing. - src/lib/components/ProcessedZipArchiveEditor.svelte: - Added a "PDF herunterladen" (Download PDF) button. - Added UI states to handle the merging process (loading state, error messages). - Integrated the mergeProcessedZipArchive function with the UI. - src/lib/components/AttachmentPreview.svelte: - Added a fix to ensure attachment.data is treated as a Uint8Array when loading PDF documents. --- .idea/workspace.xml | 32 ++++- package.json | 1 + pnpm-lock.yaml | 37 ++++++ src/lib/components/AttachmentPreview.svelte | 4 +- .../ProcessedZipArchiveEditor.svelte | 56 ++++++++- src/lib/zip-processing.ts | 119 ++++++++++++++++++ 6 files changed, 243 insertions(+), 6 deletions(-) diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 9444ab9..e595adb 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -3,7 +3,11 @@ - + + + + + @@ -142,7 +164,9 @@ - diff --git a/package.json b/package.json index 58a5eec..d40f0a7 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@skeletonlabs/skeleton": "^4.15.2", "@skeletonlabs/skeleton-svelte": "^4.15.2", "fflate": "^0.8.3", + "pdf-lib": "^1.17.1", "pdfjs-dist": "^6.0.227" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9df5cc..dcafeaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: fflate: specifier: ^0.8.3 version: 0.8.3 + pdf-lib: + specifier: ^1.17.1 + version: 1.17.1 pdfjs-dist: specifier: ^6.0.227 version: 6.0.227 @@ -187,6 +190,12 @@ packages: '@oxc-project/types@0.133.0': resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@pdf-lib/standard-fonts@1.0.0': + resolution: {integrity: sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==} + + '@pdf-lib/upng@1.0.1': + resolution: {integrity: sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==} + '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} @@ -798,6 +807,12 @@ packages: resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} engines: {node: '>=12.20.0'} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + pdf-lib@1.17.1: + resolution: {integrity: sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==} + pdfjs-dist@6.0.227: resolution: {integrity: sha512-/P6M4SXw+70waMVLUM7rdRtvo+dEzqE1t6W/zQNvBETo2MaRa5rrvCcAYdfWGiUzadTgM0lJmRApUrW0d9zgKg==} engines: {node: '>=22.13.0 || >=24'} @@ -938,6 +953,9 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1112,6 +1130,14 @@ snapshots: '@oxc-project/types@0.133.0': {} + '@pdf-lib/standard-fonts@1.0.0': + dependencies: + pako: 1.0.11 + + '@pdf-lib/upng@1.0.1': + dependencies: + pako: 1.0.11 + '@polka/url@1.0.0-next.29': {} '@rolldown/binding-android-arm64@1.0.3': @@ -1786,6 +1812,15 @@ snapshots: obug@2.1.2: {} + pako@1.0.11: {} + + pdf-lib@1.17.1: + dependencies: + '@pdf-lib/standard-fonts': 1.0.0 + '@pdf-lib/upng': 1.0.1 + pako: 1.0.11 + tslib: 1.14.1 + pdfjs-dist@6.0.227: optionalDependencies: '@napi-rs/canvas': 1.0.0 @@ -1902,6 +1937,8 @@ snapshots: totalist@3.0.1: {} + tslib@1.14.1: {} + tslib@2.8.1: {} typescript@6.0.3: {} diff --git a/src/lib/components/AttachmentPreview.svelte b/src/lib/components/AttachmentPreview.svelte index a198a16..eadfa78 100644 --- a/src/lib/components/AttachmentPreview.svelte +++ b/src/lib/components/AttachmentPreview.svelte @@ -50,7 +50,9 @@ } try { - const loadingTask = getDocument({ data: attachment.data }); + // create a copy, getDocument seems to manipulate the data -> creating pdfs fails + const buffer = new Uint8Array(attachment.data); + const loadingTask = getDocument({ data: buffer }); const pdfDocument = await loadingTask.promise; const page = await pdfDocument.getPage(1); diff --git a/src/lib/components/ProcessedZipArchiveEditor.svelte b/src/lib/components/ProcessedZipArchiveEditor.svelte index f7fe174..bd55993 100644 --- a/src/lib/components/ProcessedZipArchiveEditor.svelte +++ b/src/lib/components/ProcessedZipArchiveEditor.svelte @@ -1,6 +1,6 @@