diff --git a/.github/scripts/annotate-report.ps1 b/.github/scripts/annotate-report.ps1 new file mode 100644 index 0000000000..f22c9b294f --- /dev/null +++ b/.github/scripts/annotate-report.ps1 @@ -0,0 +1,26 @@ +# Publishes a text report as GitHub Actions annotations (which, unlike logs, the checks API returns): +# chunks First .. First+9 of about 3000 characters each, titled " part N of M". +param( + [Parameter(Mandatory = $true)] [string] $Path, + [int] $First = 0, + [string] $Kind = 'notice' +) +if (-not (Test-Path -LiteralPath $Path)) { Write-Output "::$Kind title=report::$Path was not written"; exit 0 } +$text = (Get-Content -LiteralPath $Path -Raw) -replace "`r", '' +$size = 3000 +$chunks = [System.Collections.Generic.List[string]]::new() +$start = 0 +while ($start -lt $text.Length) { + $len = [Math]::Min($size, $text.Length - $start) + if ($start + $len -lt $text.Length) { + $cut = $text.LastIndexOf("`n", $start + $len - 1, $len) + if ($cut -gt $start) { $len = $cut - $start + 1 } + } + $chunks.Add($text.Substring($start, $len)) + $start += $len +} +$name = Split-Path -Leaf $Path +for ($i = $First; $i -lt [Math]::Min($First + 10, $chunks.Count); $i++) { + $msg = $chunks[$i] -replace '%', '%25' -replace "`n", '%0A' + Write-Output "::$Kind title=$name part $($i + 1) of $($chunks.Count)::$msg" +} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index af34d040d7..34440cfd54 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,7 +60,7 @@ jobs: echo "date=$(date -u +%Y-%m-%d)" echo "prerelease=$pre" } >>"$GITHUB_OUTPUT" - echo "### PdfCraft v$v (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY" + echo "### Linkco PDF Editor v$v (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY" macos: name: macOS universal @@ -488,7 +488,7 @@ jobs: working-directory: artifacts run: | tag="v$VERSION" - title="PdfCraft v$VERSION" + title="Linkco PDF Editor v$VERSION" pre=() if [ "$PRERELEASE" = true ]; then pre=(--prerelease); fi if draft="$(gh release view "$tag" --json isDraft --jq .isDraft 2>/dev/null)"; then diff --git a/.github/workflows/windows-arm64.yml b/.github/workflows/windows-arm64.yml index 2ddcf82a27..83cf5184c4 100644 --- a/.github/workflows/windows-arm64.yml +++ b/.github/workflows/windows-arm64.yml @@ -83,11 +83,11 @@ jobs: $p = Start-Process msiexec.exe -ArgumentList '/i', "`"$msi`"", '/qn', '/l*v', 'install.log' -Wait -PassThru if ($p.ExitCode -ne 0) { Get-Content install.log -Tail 60; throw "msiexec /i exited $($p.ExitCode)" } $shortcuts = @( - (Join-Path ([Environment]::GetFolderPath('CommonPrograms')) 'PdfCraft.lnk'), - (Join-Path ([Environment]::GetFolderPath('CommonDesktopDirectory')) 'PdfCraft.lnk') + (Join-Path ([Environment]::GetFolderPath('CommonPrograms')) 'Linkco PDF Editor.lnk'), + (Join-Path ([Environment]::GetFolderPath('CommonDesktopDirectory')) 'Linkco PDF Editor.lnk') ) # Plain shortcuts to the program (#143), not advertised ones, so TargetPath is the exe. - $exePath = Join-Path $env:ProgramFiles 'PdfCraft\pdfcraft.exe' + $exePath = Join-Path $env:ProgramFiles 'Linkco\Linkco PDF Editor\pdfcraft.exe' $wsh = New-Object -ComObject WScript.Shell foreach ($shortcut in $shortcuts) { if (-not (Test-Path -LiteralPath $shortcut)) { throw "installer did not create $shortcut" } @@ -95,7 +95,7 @@ jobs: if ($target -ne $exePath) { throw "$shortcut points to '$target', not $exePath" } Write-Output "ok $shortcut -> $target" } - $dir = Join-Path $env:ProgramFiles 'PdfCraft' + $dir = Join-Path $env:ProgramFiles 'Linkco\Linkco PDF Editor' foreach ($exe in 'pdfcraft.exe', 'pdfcraft-cli.exe') { $path = Join-Path $dir $exe if (-not (Test-Path $path)) { Get-ChildItem -Recurse $env:ProgramFiles -Filter $exe | Select-Object -First 3; throw "$exe not installed in $dir" } diff --git a/.github/workflows/windows-preview-handler.yml b/.github/workflows/windows-preview-handler.yml new file mode 100644 index 0000000000..44255496a9 --- /dev/null +++ b/.github/workflows/windows-preview-handler.yml @@ -0,0 +1,63 @@ +name: Windows preview handler + +# Hosts the File Explorer PDF preview handler on a real Windows machine the way Explorer does +# (packaging/windows/test-preview-host.ps1) and publishes the step-by-step report as annotations. + +on: + pull_request: + paths: + - packaging/windows/** + - apps/pdfcraft-cli/** + - .github/workflows/windows-preview-handler.yml + workflow_dispatch: + +concurrency: + group: preview-handler-${{ github.ref }} + cancel-in-progress: true + +jobs: + host: + name: preview handler (${{ matrix.engine }}) + runs-on: windows-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + engine: [no engine, pdfcraft-cli] + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + if: matrix.engine == 'pdfcraft-cli' + + - uses: Swatinem/rust-cache@v2 + if: matrix.engine == 'pdfcraft-cli' + + - name: Build pdfcraft-cli + if: matrix.engine == 'pdfcraft-cli' + run: cargo build --release -p pdfcraft-cli + + - name: Host the preview handler like File Explorer + shell: powershell + run: | + $testArgs = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', 'packaging\windows\test-preview-host.ps1', '-Report', 'preview-host-report.txt') + if ('${{ matrix.engine }}' -eq 'pdfcraft-cli') { $testArgs += @('-Cli', 'target\release\pdfcraft-cli.exe') } + $ErrorActionPreference = 'Continue' + & powershell @testArgs *>&1 | ForEach-Object { "$_" } | Tee-Object -FilePath host-output.txt + $code = $LASTEXITCODE + if (-not (Test-Path preview-host-report.txt)) { Copy-Item host-output.txt preview-host-report.txt } + exit $code + + # Annotations are readable through the API; at most 10 per type and step, so split the report. + - name: Report (1) + if: always() + shell: pwsh + run: ./.github/scripts/annotate-report.ps1 -Path preview-host-report.txt -First 0 -Kind notice + - name: Report (2) + if: always() + shell: pwsh + run: ./.github/scripts/annotate-report.ps1 -Path preview-host-report.txt -First 10 -Kind notice + - name: Report (3) + if: always() + shell: pwsh + run: ./.github/scripts/annotate-report.ps1 -Path preview-host-report.txt -First 20 -Kind notice diff --git a/.gitignore b/.gitignore index 7834b668cb..150867828c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ plan/ /assets/models # A craft-fonts checkout used as the optional CRAFT_FONTS_DIR build input (CI and releases put it here). /craft-fonts + +__pycache__/ +*.pyc diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 28bd17c7c8..999bc8eb4a 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -4,7 +4,7 @@ Every asset PdfCraft includes, bundles or uses to build its published material, with its author, source and licence. The policy is in [AGENTS.md](AGENTS.md) §1. The machine-readable list, with SHA-256 hashes, is [ATTRIBUTION.toml](ATTRIBUTION.toml). Licence texts are kept beside the assets and summarised in [NOTICE](NOTICE). -## In this repository (264) +## In this repository (245) | Asset | Title | Author | Licence | Source | Used for | |---|---|---|---|---|---| @@ -219,43 +219,22 @@ Every asset PdfCraft includes, bundles or uses to build its published material, | `vendor/hayro-interpret/assets/FoxitSymbol.pfb` | FoxitSymbol (standard-14 substitute font) | Foxit Software Inc. / PDFium Authors | BSD-3-Clause | https://pdfium.googlesource.com/pdfium (via hayro-interpret 0.7.0 assets/) | Renders non-embedded standard-14 fonts (vendored hayro-interpret) | | `vendor/hayro-interpret/assets/CGATS001Compat-v2-micro.icc` | CGATS001Compat v2 micro ICC profile | Clinton Ingram (saucecontrol/Compact-ICC-Profiles) | CC0-1.0 | https://github.com/saucecontrol/Compact-ICC-Profiles | Default CMYK colour conversion (vendored hayro-interpret) | | `vendor/hayro-interpret/assets/LAB.icc` | Lab abstract ICC profile | The Hayro Authors (generated with LittleCMS 2) | MIT OR Apache-2.0 | https://github.com/LaurenzV/hayro (hayro-interpret 0.7.0 assets/) | Lab colour space conversion (vendored hayro-interpret) | -| `docs/brand/artcraft-logo-white.png` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `docs/brand/artcraft-logo-white.svg` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `docs/brand/artcraft-logo.png` | ArtCraft brand: artcraft-logo | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `docs/brand/artcraft-logo.svg` | ArtCraft brand: artcraft-logo | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `docs/brand/artcraft-mark-black.png` | ArtCraft brand: artcraft-mark-black | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `docs/brand/artcraft-mark-black.svg` | ArtCraft brand: artcraft-mark-black | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `docs/brand/artcraft-mark.png` | ArtCraft brand: artcraft-mark | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `docs/brand/artcraft-mark.svg` | ArtCraft brand: artcraft-mark | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | -| `assets/app-icon/pdfcraft.svg` | PdfCraft app icon (master vector) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Master artwork; every other app-icon file is rendered from it (packaging/icons.sh) | -| `assets/app-icon/pdfcraft-small.svg` | PdfCraft app icon (light vector) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | README header and assets/app-icon/README.md | -| `assets/app-icon/pdfcraft-1024.png` | PdfCraft app icon, 1024 px on Apple's icon grid | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Runtime window/Dock icon on macOS (apps/pdfcraft/src/main.rs) | -| `assets/app-icon/pdfcraft.icns` | PdfCraft app icon (macOS .icns) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | macOS app bundle icon | -| `assets/app-icon/pdfcraft.ico` | PdfCraft app icon (Windows .ico, 16-256 px) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Embedded in pdfcraft.exe by apps/pdfcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab) | -| `assets/app-icon/pdfcraft-document.svg` | PdfCraft PDF document icon (master vector) | Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition) | ISC AND (MIT OR Apache-2.0) | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition (assets/app-icon/README.md) | Master artwork for the Windows PDF file type icon; rendered by packaging/icons.sh, without fonts or external images | -| `assets/app-icon/pdfcraft-document.ico` | PdfCraft PDF document icon (Windows .ico, 16-256 px) | Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition) | ISC AND (MIT OR Apache-2.0) | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition (assets/app-icon/README.md) | Embedded in pdfcraft.exe as resource 2; the Windows installer uses it for PdfCraft.Document and Applications/pdfcraft.exe PDF file associations | -| `assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 16 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 24 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 32 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 48 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 64 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 128 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 256 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop); runtime window icon on Windows and Linux (apps/pdfcraft/src/main.rs) | -| `assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 512 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg` | PdfCraft app icon (Linux scalable) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | -| `docs/images/pdfcraft-bookmarks.png` | PdfCraft screenshot: Bookmarks | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-dark.png` | PdfCraft screenshot: Dark theme | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-find.png` | PdfCraft screenshot: Find text | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-forms.png` | PdfCraft screenshot: Interactive form | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-layers.png` | PdfCraft screenshot: Layers | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-organize.png` | PdfCraft screenshot: Organize pages | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-palette.png` | PdfCraft screenshot: Command palette | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-properties.png` | PdfCraft screenshot: Document properties | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-scripts.png` | PdfCraft screenshot: Scripts of the world | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-split.png` | PdfCraft screenshot: Split dialog | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-tools.png` | PdfCraft screenshot: All tools | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tool catalogue. Shows PdfCraft UI, Lucide icons, the showcase PDF built from the [[fetched]] OFL fonts, and the ArtCraft mark (Storyteller trademark from docs/brand/, not covered by this licence) | -| `docs/images/pdfcraft-twoup.png` | PdfCraft screenshot: Two-up reading | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | -| `docs/images/pdfcraft-viewer.png` | PdfCraft screenshot: Viewer with comments | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts | +| `assets/app-icon/pdfcraft.svg` | Linkco PDF Editor app icon (master vector) | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Master artwork; every other app-icon file is rendered from it (packaging/icons.sh) | +| `assets/app-icon/pdfcraft-small.svg` | Linkco PDF Editor app icon (light vector) | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | README header and assets/app-icon/README.md | +| `assets/app-icon/pdfcraft-1024.png` | Linkco PDF Editor app icon, 1024 px on Apple's icon grid | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Runtime window/Dock icon on macOS (apps/pdfcraft/src/main.rs) | +| `assets/app-icon/pdfcraft.icns` | Linkco PDF Editor app icon (macOS .icns) | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | macOS app bundle icon | +| `assets/app-icon/pdfcraft.ico` | Linkco PDF Editor app icon (Windows .ico, 16-256 px) | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Embedded in pdfcraft.exe by apps/pdfcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab) | +| `assets/app-icon/pdfcraft-document.svg` | Linkco PDF Editor PDF document icon (master vector) | Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition); Al Rawabet Commercial Services & Contracting Company W.L.L. (Linkco colours) | ISC AND (MIT OR Apache-2.0) | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition, recoloured to the Linkco palette (assets/app-icon/README.md) | Master artwork for the Windows PDF file type icon; rendered by packaging/icons.sh, without fonts or external images | +| `assets/app-icon/pdfcraft-document.ico` | Linkco PDF Editor PDF document icon (Windows .ico, 16-256 px) | Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition); Al Rawabet Commercial Services & Contracting Company W.L.L. (Linkco colours) | ISC AND (MIT OR Apache-2.0) | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition, recoloured to the Linkco palette (assets/app-icon/README.md) | Embedded in LinkcoPDFEditor.exe (pdfcraft.exe) as resource 2; the Windows installers use it for the LinkcoPDFEditor.Document and Applications PDF file associations | +| `assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 16 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | +| `assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 24 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | +| `assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 32 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | +| `assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 48 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | +| `assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 64 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | +| `assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 128 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | +| `assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 256 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop); runtime window icon on Windows and Linux (apps/pdfcraft/src/main.rs) | +| `assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png` | Linkco PDF Editor app icon, 512 px | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | +| `assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg` | Linkco PDF Editor app icon (Linux scalable) | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | Original Linkco PDF Editor brand asset (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) | | `assets/icons/pin.svg` | Lucide icon "pin" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pin.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | | `assets/icons/move-right.svg` | Lucide icon "move-right" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-right.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | | `assets/icons/reply.svg` | Lucide icon "reply" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/reply.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | @@ -272,6 +251,8 @@ Every asset PdfCraft includes, bundles or uses to build its published material, | `packaging/macos/dmg/background.svg` | PdfCraft macOS DMG window background | @XusBadia | MIT OR Apache-2.0 | Original work for this repository, derived from the PdfCraft app icon (assets/app-icon/pdfcraft.svg, referenced via an SVG image element, not copied) | Finder window of the macOS DMG; rendered to background.tiff by packaging/macos/dmg/generate.py | | `packaging/macos/dmg/background.tiff` | PdfCraft macOS DMG window background (rendered) | @XusBadia | MIT OR Apache-2.0 | Rendered from packaging/macos/dmg/background.svg by packaging/macos/dmg/generate.py | 1x + 2x HiDPI 16-colour palette TIFF copied into the macOS DMG by packaging/macos/package.sh; includes the app icon and the free LittleCMS built-in sRGB profile | | `crates/sign/tests/data/x509-rsa-sha1.pdf` | One-page PDF with a legacy adbe.x509.rsa_sha1 signature by the RSA test key | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl dgst -sha1 -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/pdf.rs): the legacy adbe.x509.rsa_sha1 format | +| `docs/images/linkco-home-dashboard.png` | Linkco PDF Editor screenshot: Home dashboard and Recommended Tools | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | this repository | README: Home dashboard and Recommended Tools screenshot | +| `docs/images/linkco-organize-pages.png` | Linkco PDF Editor screenshot: Organize pages view | Al Rawabet Commercial Services & Contracting Company W.L.L. | MIT OR Apache-2.0 | this repository | README: Organize pages screenshot | ## Compiled in through dependencies (6) diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml index cfa2e43402..71fd733861 100644 --- a/ATTRIBUTION.toml +++ b/ATTRIBUTION.toml @@ -19,7 +19,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "2c0f7bc1c225a95d2322e5f92e42ca3b07652f54976d754e9901abeddc4d0dc6" +sha256 = "543246cc34daad6ae9c1d720e814b07e7b84102bda65b5187c6ca79fcf71cd37" [[asset]] path = "crates/ui-egui/src/i18n/zh-hant.tsv" @@ -30,7 +30,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "b55ec8f2794966e879334121d48b15923cebf38192bd8e1667d4c4e6bf168095" +sha256 = "cad64a460acedcc339ab7419bfe814be7dd1c4828987d764692120b561b5f27e" [[asset]] path = "crates/ui-egui/src/i18n/cs.tsv" @@ -41,7 +41,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Czech UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "abd8d0c409be846fcf48cbc1338def7f77f2d301bd84d863e4ad66434e5f821f" +sha256 = "97c47ef1aea495b54e28c8e4f69ed389e148b5d1eaeb4d0d8f25679a0a27d606" [[asset]] path = "crates/ui-egui/src/i18n/pt-br.tsv" @@ -52,7 +52,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "fe8fc8af29190950048c3e3d5108ede6cf2da2f85ed7003fb2035ddb517a600c" +sha256 = "2850181d4203358a65714ed06e3c48f9b0596ed1d3262c1cad32c9633eb3ddac" [[asset]] path = "crates/ui-egui/src/i18n/es.tsv" @@ -63,7 +63,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Spanish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "81ce4a9a18d10149129ecdf7eb0e0d3179cb4a66cf3f344a32de9a984612dafa" +sha256 = "193cba9df6911994fed5e121796e406713310517c3f6919ccfe086d1d6f45fae" [[asset]] path = "crates/ui-egui/src/i18n/fr.tsv" @@ -74,7 +74,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "French UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "6d99c6a85e69b5448609ae54847700c908919be27d904bd0c73bf2c220a2da4e" +sha256 = "a618a69409013e7014abcced61c2fa29a3edcc5eb56ee8e0aea6826246e466a4" [[asset]] path = "crates/ui-egui/src/i18n/de.tsv" @@ -85,7 +85,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "German UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "09f654d07a87878802e87fc0436f9a5426bc27bfb2156aee912463c5dc8a04ea" +sha256 = "340b6b94970460baf69aa636e64b1f71a969e29a805a4cc1fa2bec5c9369ba41" [[asset]] path = "crates/ui-egui/src/i18n/te.tsv" @@ -96,7 +96,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Telugu UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "fd2b1b33d940ff9eef4bc067452252c39bf6cf02f3fe22e84ecd782943d2cc26" +sha256 = "f790f05b752a85d0bbfcecd64d8db20ef40b295ef77264dc365725fe2d6d6cd4" [[asset]] path = "crates/ui-egui/src/i18n/it.tsv" @@ -107,7 +107,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Italian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "8a7a2bfba1a2f9858ad62a74bd8229a1615a5bc6e51023b11b9768e7ea21d79c" +sha256 = "f1abb07f3997aa1254fa315de1492a0df781422d09ddec6ae22ac4439728fa8f" [[asset]] path = "crates/ui-egui/src/i18n/pl.tsv" @@ -118,7 +118,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Polish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "95e35de200c66936333a95d89561f3c4d32b1d38f9c0a8357bec5c6b0e75fe1e" +sha256 = "c32882597659958bad8364b3f96eec5a5410a60c18b0ae645b2062cd359f6da9" [[asset]] path = "crates/ui-egui/src/i18n/ru.tsv" @@ -129,7 +129,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Russian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "dc0af15b819b9059bc23a73a1e794d1ae5291594b2ff0fae2595274fccc9c281" +sha256 = "4cc3021953fe6672a5288bc0ce9a7551284d747dc52ac3af78f9bf35b7ec6af9" [[asset]] path = "crates/ui-egui/src/i18n/hu.tsv" @@ -140,7 +140,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Hungarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "16c6e6cf857b70f7ade009bc9c87fceb3831f5f3281ac7fabc0fd7bfd2c5d28e" +sha256 = "256a34a221d2276cee05b7f6c2ba966241108a2a218f9c3dbf828fa9f4a202eb" [[asset]] path = "crates/ui-egui/src/i18n/bg.tsv" @@ -151,7 +151,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "9e8c0929c5839b2a5f5c93a2d3457bcce24b118a11fd6b37476aa3584fa5ce76" +sha256 = "c4f4b9cf80ceabeee39849b74741c2b64391015b28489ae84d6a56ebf4d966dc" [[asset]] path = "crates/ui-egui/src/i18n/ja.tsv" @@ -162,7 +162,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "47720091895fc1a4c1ff332a660192fe4a9666f32002e5899030b3ca3421f337" +sha256 = "9c85d4bd2009968438bf277ec39ab316b790739a7a2c34ef3808ee232aa31934" [[asset]] path = "crates/ui-egui/src/i18n/uk.tsv" @@ -173,7 +173,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "fa2f00414a8f064f4d6e47d57702a100743c8b64b05dcbe93585330427c83f16" +sha256 = "0334550c99e035dbce9bb8e4c8c502ca7a0b1e1494593b7b288543e5a9d466fd" [[asset]] path = "crates/ui-egui/src/i18n/ar.tsv" @@ -184,7 +184,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Arabic UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "271a9b34b0d13d1734de53d88a09b49d589eb556c75fe04dd1fa5172151c5b1a" +sha256 = "de786a2d8acb03638f7c95a01953dfd19629064af839a6af037853af02ac3832" [[asset]] path = "assets/icons/accessibility.svg" @@ -2331,912 +2331,713 @@ kind = "data" usage = "Lab colour space conversion (vendored hayro-interpret)" sha256 = "a6efc5c30ece826eba2a83ddf5aa7026289b0c5ffa90acb129bc59ab8d7f5c59" -[[bundled]] -crate = "epaint_default_fonts" -version = "0.36.2" -path = "fonts/Ubuntu-Light.ttf" -title = "Ubuntu Light" -author = "Canonical Ltd. / Dalton Maag" -source = "https://design.ubuntu.com/font" -licence = "Ubuntu-font-1.0" -kind = "font" -usage = "egui fallback fonts (eframe feature default_fonts)" -sha256 = "80307b8da7649aa4ee4d484b232140e3ce1ec0ca093073d3c53c8f5a5ced7a70" - -[[bundled]] -crate = "epaint_default_fonts" -version = "0.36.2" -path = "fonts/Hack-Regular.ttf" -title = "Hack Regular" -author = "Source Foundry Authors (derived from Bitstream Vera / DejaVu)" -source = "https://github.com/source-foundry/Hack" -licence = "MIT AND Bitstream-Vera" -kind = "font" -usage = "egui fallback fonts (eframe feature default_fonts)" -sha256 = "15f55cc0c85a2988d2b4b3a8cdb5d77fdfbaf319e1bb5309d725db9818fb7125" - -[[bundled]] -crate = "epaint_default_fonts" -version = "0.36.2" -path = "fonts/NotoEmoji-Regular.ttf" -title = "Noto Emoji (monochrome)" -author = "Google Inc." -source = "https://github.com/googlefonts/noto-emoji" -licence = "OFL-1.1" -kind = "font" -usage = "egui fallback fonts (eframe feature default_fonts)" -sha256 = "415dc6290378574135b64c808dc640c1df7531973290c4970c51fdeb849cb0c5" - -[[bundled]] -crate = "epaint_default_fonts" -version = "0.36.2" -path = "fonts/emoji-icon-font.ttf" -title = "emoji-icon-font" -author = "John Slegers" -source = "https://github.com/jslegers/emoji-icon-font" -licence = "MIT" -kind = "font" -usage = "egui fallback fonts (eframe feature default_fonts)" -sha256 = "f426bec371f484646d002717e2c555a95cd5145e635d83a48bbef83f3abf18ca" - -[[bundled]] -crate = "hayro-cmap" -version = "0.1.0" -path = "assets/cmaps.brotli" -title = "Adobe CMap resources (predefined CJK CMaps)" -author = "Adobe" -source = "https://github.com/adobe-type-tools/cmap-resources (via hayro-cmap)" -licence = "BSD-3-Clause" -kind = "data" -adobe_data = true -usage = "Character-code mapping tables required to read CJK PDFs. Non-visual data, allowed by AGENTS.md §1.1" -sha256 = "ddf37af521d904d5646c2fc37b2b7e912dc1b56f0d210190b61f598154758e46" - -[[bundled]] -crate = "hayro-interpret" -version = "0.7.0" -path = "src/font/generated/metrics.rs" -title = "Standard-14 font metrics and encodings (as Rust tables)" -author = "Adobe (Core 14 AFM metrics, PDF specification encodings); tables by The Hayro Authors" -source = "ISO 32000-2 Annex D; Adobe Core14 AFM files (via vendored hayro-interpret)" -licence = "MIT OR Apache-2.0" -kind = "data" -adobe_data = true -usage = "Glyph widths and encodings for non-embedded standard fonts. Non-visual data, allowed by AGENTS.md §1.1" -sha256 = "2ec9e608573eda459de1e1d9bda3bb494315e36bee885acc88912a11fe0caa41" - -[[fetched]] -file = "PlayfairDisplay[wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/PlayfairDisplay%5Bwght%5D.ttf" -title = "Playfair Display" -author = "The Playfair Display Project Authors (Claus Eggers Sørensen)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/OFL.txt" -licence_sha256 = "566be814f8e96e93dfa16101331557eb6b5467e9e03f627c0910fe93ca12300e" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "c40f2293766a503bc70cce9e512ef844a4ccb7cbcde792fe2ea31d191917d8d6" - -[[fetched]] -file = "PlayfairDisplay-Italic[wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/PlayfairDisplay-Italic%5Bwght%5D.ttf" -title = "Playfair Display Italic" -author = "The Playfair Display Project Authors (Claus Eggers Sørensen)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/OFL.txt" -licence_sha256 = "566be814f8e96e93dfa16101331557eb6b5467e9e03f627c0910fe93ca12300e" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "a5e26dc5e2e77fb2803a0bf02fd4f81ee136ec8dea863ccdb0c59a263b21378b" - -[[fetched]] -file = "EBGaramond[wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/EBGaramond%5Bwght%5D.ttf" -title = "EB Garamond" -author = "The EB Garamond Project Authors (Georg Duffner, Octavio Pardo)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/OFL.txt" -licence_sha256 = "0985066662eb755ed3683ae5482a81a9195b49ce3f7e165cc2388b3dbece7dd7" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "ef9512f92f6d579e5dc75af59a5a4b1b8b47d2eda89e00b954d44520e5369027" - -[[fetched]] -file = "EBGaramond-Italic[wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/EBGaramond-Italic%5Bwght%5D.ttf" -title = "EB Garamond Italic" -author = "The EB Garamond Project Authors (Georg Duffner, Octavio Pardo)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/OFL.txt" -licence_sha256 = "0985066662eb755ed3683ae5482a81a9195b49ce3f7e165cc2388b3dbece7dd7" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "bba2c4499c93c9612b90b9825d32b07da52fce2fe57562a1eb6b833553f93c4e" - -[[fetched]] -file = "GreatVibes-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/greatvibes/GreatVibes-Regular.ttf" -title = "Great Vibes" -author = "The Great Vibes Pro Project Authors (TypeSETit)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/greatvibes" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/greatvibes/OFL.txt" -licence_sha256 = "61093a21f5e63dedf54222b3c09997e54c0fe43e3851d21386e02ddcbc246d49" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "8d509802186f1b51572531ecf313e8098f9a5bfdfaca93f0c9b34467f9982d15" - -[[fetched]] -file = "STIXTwoMath-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/stixtwomath/STIXTwoMath-Regular.ttf" -title = "STIX Two Math" -author = "The STIX Fonts Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/stixtwomath" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/stixtwomath/OFL.txt" -licence_sha256 = "0c8825913b60d858aacdb33c4ca6660a7d64b0d6464702efbb19313f5765861a" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "562551b15b836e6e01d1b7350909baf3c8c8d83260c1190fbf4544333e6936de" - -[[fetched]] -file = "Amiri-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/amiri/Amiri-Regular.ttf" -title = "Amiri" -author = "The Amiri Project Authors (Khaled Hosny)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/amiri" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/amiri/OFL.txt" -licence_sha256 = "72de68e5954f4fdd24702292ef5a32f003ca960ec9330dc86e5eefb5dffb9b22" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "ab391c4147d054c48976e98322ad0eefe1427aa0e0502a12a4c75d80a70cfcd7" - -[[fetched]] -file = "NotoSansHebrew[wdth,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanshebrew/NotoSansHebrew%5Bwdth%2Cwght%5D.ttf" -title = "Noto Sans Hebrew" -author = "The Noto Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanshebrew" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanshebrew/OFL.txt" -licence_sha256 = "9b9fe028b5ba74d231659a1bbaf0ed09b11e759d1ca6a070999e16d151616b47" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "7ef36a2c3593758cdb622e1bdef4f84523e92fbc3ccc667438dd80ff54c2de88" - -[[fetched]] -file = "NotoSansDevanagari[wdth,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansdevanagari/NotoSansDevanagari%5Bwdth%2Cwght%5D.ttf" -title = "Noto Sans Devanagari" -author = "The Noto Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansdevanagari" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansdevanagari/OFL.txt" -licence_sha256 = "a216f6f8d85c7228093e0ee5e258d9d377e6671f68acb4db1930b29583d0f331" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "14ec4af41f27482216d1c2229f417ff9b1425e1babb014e57d1d40d03229853e" - -[[fetched]] -file = "NotoSansThai[wdth,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansthai/NotoSansThai%5Bwdth%2Cwght%5D.ttf" -title = "Noto Sans Thai" -author = "The Noto Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansthai" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansthai/OFL.txt" -licence_sha256 = "2e98fd23a52d253db8612cd5942c8f2ff4111b21d2367050fdca91d8ccc374a0" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "5a1c559bb539583c8a1fd99d1c5b9491e5e14478c9cd2bd0970d5c3096cc9ef8" - -[[fetched]] -file = "NotoSansArmenian[wdth,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansarmenian/NotoSansArmenian%5Bwdth%2Cwght%5D.ttf" -title = "Noto Sans Armenian" -author = "The Noto Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansarmenian" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansarmenian/OFL.txt" -licence_sha256 = "0468358b316f69f405b55cadf8a8314e16e3610b8feaad96772bd5d968112d02" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "0870908d8318435a5daf1cd280ae15063f990cd9ad60f3e94c734ce9e1ffef71" - -[[fetched]] -file = "NotoSansGeorgian[wdth,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansgeorgian/NotoSansGeorgian%5Bwdth%2Cwght%5D.ttf" -title = "Noto Sans Georgian" -author = "The Noto Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansgeorgian" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansgeorgian/OFL.txt" -licence_sha256 = "8c02263c5d73d40544f9ed91e30c4e947407057a3cc430d7b786189aeceff6df" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "dc591156f36842d38996c4a7a17fee9bb58e45da3e2cac7a31b7d33de700adb9" - -[[fetched]] -file = "NotoSansTamil[wdth,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanstamil/NotoSansTamil%5Bwdth%2Cwght%5D.ttf" -title = "Noto Sans Tamil" -author = "The Noto Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanstamil" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanstamil/OFL.txt" -licence_sha256 = "f8ff8ce7d0a81bf8d5e121c635ef027250c531f2fd37d5988b8dd6e45f19d7f1" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "aa3a9b321f4b0bb2c40203ffbde9af89713227866e0e13f76e5b9eeea727cf88" - -[[fetched]] -file = "CharisSIL-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/charissil/CharisSIL-Regular.ttf" -title = "Charis SIL" -author = "SIL International" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/charissil" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/charissil/OFL.txt" -licence_sha256 = "0acda775b4dedaf980821f590206a692779ee495170018ee2b9caf1c50fc136a" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "346337374aa347d64ee015b26d441f1970d8631914e2f3941b00e1c4761e28c5" - -[[fetched]] -file = "ZCOOLXiaoWei-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/zcoolxiaowei/ZCOOLXiaoWei-Regular.ttf" -title = "ZCOOL XiaoWei" -author = "The ZCOOL XiaoWei Project Authors" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/zcoolxiaowei" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/zcoolxiaowei/OFL.txt" -licence_sha256 = "a094514ca57cf8f9c5e8d8d1adab5d8cd3a377297ff016f9df2c05b3ecd77f0a" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "a42b620140f493db42f741351dfbf343c0936d58588ee8004b8b2a218d997ff1" - -[[fetched]] -file = "ShipporiMincho-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/shipporimincho/ShipporiMincho-Regular.ttf" -title = "Shippori Mincho" -author = "The Shippori Mincho Project Authors (FONTDASU)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/shipporimincho" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/shipporimincho/OFL.txt" -licence_sha256 = "41fba056279be5f45ff9a99e44b7b53897b42732f5806d8e666e0ab49ac6bd38" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "769b5269f0f9bc6534b352c0e6bd856a566e03ff788f107191c2d835863570b2" - -[[fetched]] -file = "GowunBatang-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/gowunbatang/GowunBatang-Regular.ttf" -title = "Gowun Batang" -author = "The Gowun Batang Project Authors (Yanghee Ryu)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/gowunbatang" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/gowunbatang/OFL.txt" -licence_sha256 = "49a57cc769fa9affd6eefb9070a61e3d3f6b757c97cafb15848bc6d1c81acc78" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "466c593e7147412e748af4856d5ad14709b5a860bdf62b9c2546f2c5874e9849" - -[[fetched]] -file = "NotoColorEmoji-Regular.ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notocoloremoji/NotoColorEmoji-Regular.ttf" -title = "Noto Color Emoji" -author = "Google Inc." -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notocoloremoji" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notocoloremoji/OFL.txt" -licence_sha256 = "ac564676d10054a8445923dfc2dfb13c042d97888bd27c1b6ec6dfe89a9d8d62" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "4d82a18d8d95f60ba883ce242bbadbf84a576e987745dd7ba38d71c67cff2d73" - -[[fetched]] -file = "Inter[opsz,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/Inter%5Bopsz%2Cwght%5D.ttf" -title = "Inter (variable)" -author = "The Inter Project Authors (Rasmus Andersson)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/OFL.txt" -licence_sha256 = "5b9321a4298cfeb6b34354164a1c3afc3db114569984c502b9b35d988fd58c57" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "29160a80ff49ddcab2c97711247e08b1fab27a484a329ce8b813d820dc559031" - -[[fetched]] -file = "Inter-Italic[opsz,wght].ttf" -url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/Inter-Italic%5Bopsz%2Cwght%5D.ttf" -title = "Inter Italic (variable)" -author = "The Inter Project Authors (Rasmus Andersson)" -source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter" -licence = "OFL-1.1" -licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/OFL.txt" -licence_sha256 = "5b9321a4298cfeb6b34354164a1c3afc3db114569984c502b9b35d988fd58c57" -kind = "font" -usage = "Showcase PDF (cargo xtask demo-pdf)" -sha256 = "acd98e64795781b2058f07b18475e0ecee2a0fe2b42a49e2f9e37d0d6bf66ce6" - -[[asset]] -path = "docs/brand/artcraft-logo-white.png" -title = "ArtCraft brand: artcraft-logo-white" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "8b86aeb06a12a90ba77a60e0d90329272310e244ee5c1f9b161b391280ca79d8" - -[[asset]] -path = "docs/brand/artcraft-logo-white.svg" -title = "ArtCraft brand: artcraft-logo-white" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "a3e03dc49f9ad4225b8517d5424309c8d1c864d3996d862190d9cc797d5af427" - -[[asset]] -path = "docs/brand/artcraft-logo.png" -title = "ArtCraft brand: artcraft-logo" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "08fc6d9d3717e8f13417bac6f9025b50e11d1e0b32e9e000883d2fe0c4a0c67b" - -[[asset]] -path = "docs/brand/artcraft-logo.svg" -title = "ArtCraft brand: artcraft-logo" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "3188971e1affdf4f6be4fa65f715376a7a305e6aa741ec78b0296c8f934eff08" - -[[asset]] -path = "docs/brand/artcraft-mark-black.png" -title = "ArtCraft brand: artcraft-mark-black" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "5954cc0306e1b9d7beb47097e2e842157113a39d9aba078b57304902687936a9" - -[[asset]] -path = "docs/brand/artcraft-mark-black.svg" -title = "ArtCraft brand: artcraft-mark-black" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "570adcb4f7ba8ca0647f97074476bab81d3272988f1cdee52efa21bf026036a4" - -[[asset]] -path = "docs/brand/artcraft-mark.png" -title = "ArtCraft brand: artcraft-mark" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "9d372157a949c147318561e629b11561c28b7cbc14c84b516a3fe6e84d8fbbad" - -[[asset]] -path = "docs/brand/artcraft-mark.svg" -title = "ArtCraft brand: artcraft-mark" -author = "ArtCraft Team" -source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft)" -licence = "LicenseRef-Storyteller-Trademark" -licence_file = "docs/brand/LICENSE-brand.txt" -kind = "logo" -usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it." -sha256 = "f87af81b6fa411da8820eed2bfdcc54c0ee9cd453b4e868c64f56c69db142d0e" - [[asset]] path = "assets/app-icon/pdfcraft.svg" -title = "PdfCraft app icon (master vector)" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon (master vector)" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Master artwork; every other app-icon file is rendered from it (packaging/icons.sh)" -sha256 = "52b384a10a2a7fdd3145d9822972cfd568ef0cb7312549bd4399addd89d45a6d" +sha256 = "d36643c07533e6192270b24d050b90ac6956d48d3a38af30bb296833562d8005" [[asset]] path = "assets/app-icon/pdfcraft-small.svg" -title = "PdfCraft app icon (light vector)" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon (light vector)" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "README header and assets/app-icon/README.md" -sha256 = "b036304c11ef5dcad36636d06ca0bf331b51e47650d25d3c916a0e1eabf544c7" +sha256 = "b781cd71fddc3e163068b29d294f49f00e9ba9a5036ab5398df55a379ce8c7a0" [[asset]] path = "assets/app-icon/pdfcraft-1024.png" -title = "PdfCraft app icon, 1024 px on Apple's icon grid" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 1024 px on Apple's icon grid" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Runtime window/Dock icon on macOS (apps/pdfcraft/src/main.rs)" -sha256 = "da577d3f21fbcf5c739067787a9e683be2b064d76813b5d5fec9074a7a106538" +sha256 = "3d5796cae8a2f3f6c846496b77d334159bb78fd69828cd0e3cf54db49076c19d" [[asset]] path = "assets/app-icon/pdfcraft.icns" -title = "PdfCraft app icon (macOS .icns)" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon (macOS .icns)" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "macOS app bundle icon" -sha256 = "2425148222873de241d267aba667a8b234ecdd0149f2ca8bb6e79443b743b1e8" +sha256 = "452cdf80ef5b1fa8dac170fc0ac932df8e9299ce8baae5b67e19fb8a129a1e66" [[asset]] path = "assets/app-icon/pdfcraft.ico" -title = "PdfCraft app icon (Windows .ico, 16-256 px)" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon (Windows .ico, 16-256 px)" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Embedded in pdfcraft.exe by apps/pdfcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab)" -sha256 = "56daaaae9ae5389794909570885809adf5e1d9183bef2d9669ed2f9bba3ed6f5" +sha256 = "eb3c8219139bd6293d368e81a3003ad427edf7b87052d32f0258ca0b06aa3fe0" [[asset]] path = "assets/app-icon/pdfcraft-document.svg" -title = "PdfCraft PDF document icon (master vector)" -author = "Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition (assets/app-icon/README.md)" +title = "Linkco PDF Editor PDF document icon (master vector)" +author = "Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition); Al Rawabet Commercial Services & Contracting Company W.L.L. (Linkco colours)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition, recoloured to the Linkco palette (assets/app-icon/README.md)" licence = "ISC AND (MIT OR Apache-2.0)" licence_file = "assets/app-icon/LICENSE-document.txt" kind = "icon" usage = "Master artwork for the Windows PDF file type icon; rendered by packaging/icons.sh, without fonts or external images" -sha256 = "8da8278c2b89362be0a960879d453ff879d7544d6d58e47d5389574e8dfff77b" +sha256 = "0bc3e852c659cb3a75f6a51791085cc000ab1d580cab399cedb318eb7dbd4fa6" [[asset]] path = "assets/app-icon/pdfcraft-document.ico" -title = "PdfCraft PDF document icon (Windows .ico, 16-256 px)" -author = "Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition (assets/app-icon/README.md)" +title = "Linkco PDF Editor PDF document icon (Windows .ico, 16-256 px)" +author = "Lucide Icons and Contributors (document outline); PdfCraft contributors (PDF badge, lettering and composition); Al Rawabet Commercial Services & Contracting Company W.L.L. (Linkco colours)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/file-text.svg); contributor-original composition, recoloured to the Linkco palette (assets/app-icon/README.md)" licence = "ISC AND (MIT OR Apache-2.0)" licence_file = "assets/app-icon/LICENSE-document.txt" kind = "icon" -usage = "Embedded in pdfcraft.exe as resource 2; the Windows installer uses it for PdfCraft.Document and Applications/pdfcraft.exe PDF file associations" -sha256 = "ba3f9128b368fc6d17d376cf62dbdbc22455451c5c8c4779210d7a2a7409b9e6" +usage = "Embedded in LinkcoPDFEditor.exe (pdfcraft.exe) as resource 2; the Windows installers use it for the LinkcoPDFEditor.Document and Applications PDF file associations" +sha256 = "da1b8f5271b64537d17332bacfa07bd4899957778c00c7cb55ab284918c52ac4" [[asset]] path = "assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 16 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 16 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "9b77095cbe75dcba6b74a1fdcd4064812850efaf7a12edebefc9ded5eabb49da" +sha256 = "4d61a3e2ed518f80fa7fbd46a7fed3e7247c234fb6b2d6d66e01cbd0900b6312" [[asset]] path = "assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 24 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 24 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "a4cd466687f6c5cb59eef3fc564bdba1c8f0d9e324754eeebab82f18823efae7" +sha256 = "ccb8b6172617a2ef256a5b314b681569aaf1a4005599d9998277f9c60fa00454" [[asset]] path = "assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 32 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 32 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "e22279013a5ed5c02571e1e4e9bc4cef9aa0847fcb733a285b2916fabd16bf78" +sha256 = "6337c69fa9ffc967a0690b9a62644267ee61000d430830ed6bb8920e9268933c" [[asset]] path = "assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 48 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 48 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "55daf2d5575f6c4e4c4975c9f1c74231178f1801963a8b19f68dfa9bc50cb22f" +sha256 = "8f11ef187658325e106c52018a7de147f6a4fff7f78bc238442329a20237fe57" [[asset]] path = "assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 64 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 64 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "2975c200f341e247b5fa18f568fb27d390e3fa01e9b2ad37acb48d0e1cc8a124" +sha256 = "b496c777159c7fb9bb388110ca2afe1c745a558955f60992f213500f0286e9c9" [[asset]] path = "assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 128 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 128 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "6ef927ca252b40bc9b5d8843d84137334362f8aa1acbb1bf8c15a02affd25b2b" +sha256 = "ebe068c6616dcf9732daa61cbf3c5cd88c4cf37fd99b685826df29ce9fa4c2c6" [[asset]] path = "assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 256 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 256 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop); runtime window icon on Windows and Linux (apps/pdfcraft/src/main.rs)" -sha256 = "cde7ee8c5ee38f9fc40a429fd9e6d99a035bcd321701fce331bb13bac126614d" +sha256 = "2e8b582255399c1ff5c74de49040a07868f711dbd35780d1673bf88e3116ba7c" [[asset]] path = "assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png" -title = "PdfCraft app icon, 512 px" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon, 512 px" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "5ede733e93b96f4eb8d94299232cf2f9605fa19b0d913f95fe9828c316a2d066" +sha256 = "2b8e33f21552092fc2970b23d0ea751c4329c91e0664627c6c6d9930d4172c9c" [[asset]] path = "assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg" -title = "PdfCraft app icon (Linux scalable)" -author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)" -source = "Contributor-original (see assets/app-icon/README.md)" +title = "Linkco PDF Editor app icon (Linux scalable)" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." +source = "Original Linkco PDF Editor brand asset (see assets/app-icon/README.md)" licence = "MIT OR Apache-2.0" licence_file = "assets/app-icon/LICENSE.txt" kind = "icon" usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)" -sha256 = "52b384a10a2a7fdd3145d9822972cfd568ef0cb7312549bd4399addd89d45a6d" +sha256 = "d36643c07533e6192270b24d050b90ac6956d48d3a38af30bb296833562d8005" [[asset]] -path = "docs/images/pdfcraft-bookmarks.png" -title = "PdfCraft screenshot: Bookmarks" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "6daf2dceda8737da0c5f9e7895e5c4cc24cc845938ffca478713c2230573240d" +path = "assets/icons/pin.svg" +title = "Lucide icon \"pin\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pin.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "d28d42dd90e0ed601fb7120b6e0b98218289da8fc7bf41fac5ca83aeffd0ae32" [[asset]] -path = "docs/images/pdfcraft-dark.png" -title = "PdfCraft screenshot: Dark theme" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "18fbd4931b2a8d01a88aef0d5d0837e3cdc12aa35f8529bedbb4a930565d47e5" +path = "assets/icons/move-right.svg" +title = "Lucide icon \"move-right\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-right.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "d4586a7c7aea911762604211e3624b3436b998d1343b0b29162b3eddf9e6ab81" [[asset]] -path = "docs/images/pdfcraft-find.png" -title = "PdfCraft screenshot: Find text" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "b52771502be4c03e2dabf107c77d5183fad7f39655146d59761dda855c2d4b52" +path = "assets/icons/reply.svg" +title = "Lucide icon \"reply\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/reply.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "f6161386877fb29e058c85ac76f1793fb43f6fcf5144b21ef3f36a367cb41e94" [[asset]] -path = "docs/images/pdfcraft-forms.png" -title = "PdfCraft screenshot: Interactive form" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" +path = "assets/icons/thumbs-up.svg" +title = "Lucide icon \"thumbs-up\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/thumbs-up.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "e30b1dc9b4f1d56fa935ee55a4a2c9dad0eaeaffa6603085a1d3f8d5c22f60a3" + +[[asset]] +path = "assets/icons/thumbs-down.svg" +title = "Lucide icon \"thumbs-down\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/thumbs-down.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "283a01b7798806a6b9ffd19f4c449e72a08ef860281fa0d33b584b52590e7240" + +[[asset]] +path = "assets/icons/message-square-plus.svg" +title = "Lucide icon \"message-square-plus\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-plus.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "5e9d80429d9b219c98402a0d4f3194d2a0cbfe0c41dd42f46771a4d7e1c563e8" + +[[asset]] +path = "assets/icons/circle-x.svg" +title = "Lucide icon \"circle-x\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/circle-x.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "ef1fec17d88794ba6c34c5cf63bdadbd234b3d4dffbcc3d55468b47e3f398472" + +[[asset]] +path = "crates/ui-egui/tests/data/form.pdf" +title = "One-page AcroForm test fixture (text, check box, radio group, combo box)" +author = "PdfCraft contributors" +source = "Contributor-original: hand-written PDF objects, no third-party content" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "f8eb7705056d32e9c8e4d3b8b197c3e500faae08672e4622d6327d2799b536e7" +kind = "document" +usage = "Form-filling UI tests (crates/ui-egui/tests/forms.rs, commands.rs)" +sha256 = "c6f8b656e225101129aa36bd5467adc8dba16730915f19caca17f6a546d0b040" [[asset]] -path = "docs/images/pdfcraft-layers.png" -title = "PdfCraft screenshot: Layers" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" +path = "assets/icons/pentagon.svg" +title = "Lucide icon \"pentagon\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pentagon.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "55a9c2b2531928957c23e7695ccd39b096a3b3f2a5ef3e66b3ad970742e20f26" + +[[asset]] +path = "assets/icons/message-square-quote.svg" +title = "Lucide icon \"message-square-quote\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-quote.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "69a76b4cd352dbdea61c63ed1e8d1e02083ee1773b3ced2a1c8cdf8c90fb2055" + +[[asset]] +path = "crates/sign/tests/data/openssl-signed.pdf" +title = "One-page PDF signed with OpenSSL CMS (adbe.pkcs7.detached) by the RSA test key" +author = "PdfCraft contributors" +source = "Contributor-original: hand-written PDF objects; signature made with `openssl cms -sign` over its byte ranges (see crates/sign/tests/data/README.md)" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "20ff9e1c6ecc74d000a7514b82fe9e39f82c8ef5e7c1a52e9060c5ca349020d6" +kind = "document" +usage = "Signature validation tests (crates/sign/tests/pdf.rs): a signature PdfCraft did not make" +sha256 = "8b91c3b4e39c4a31717a0dd0685bd7d0468671df32aee5b9818d44dc72c2bc3c" + +[[asset]] +path = "assets/icons/clipboard-paste.svg" +title = "Lucide icon \"clipboard-paste\"" +author = "Lucide Contributors (portions Cole Bemis, Feather)" +source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/clipboard-paste.svg)" +licence = "ISC" +licence_file = "assets/icons/LICENSE-lucide.txt" +kind = "icon" +usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" +sha256 = "631d24bde604be36b2dcf3b6f86ddf6026879cdcd272c0dfe37ab0cc6b341fda" + +[[asset]] +path = "assets/fonts/DancingScript.ttf" +title = "Dancing Script (variable)" +author = "The Dancing Script Project Authors (Pablo Impallari)" +source = "https://github.com/google/fonts/blob/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/dancingscript/DancingScript%5Bwght%5D.ttf" +licence = "OFL-1.1" +licence_file = "assets/fonts/OFL-DancingScript.txt" +kind = "font" +usage = "Fill & Sign typed signatures and initials: the typed name's glyph outlines, drawn as filled paths (the font file itself is not embedded in PDFs)" +sha256 = "21808625578fe8d8cd10cb684be546dca077b27cd03a53a2f1ec11dc743c924c" [[asset]] -path = "docs/images/pdfcraft-organize.png" -title = "PdfCraft screenshot: Organize pages" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" +path = "packaging/macos/dmg/background.svg" +title = "PdfCraft macOS DMG window background" +author = "@XusBadia" +source = "Original work for this repository, derived from the PdfCraft app icon (assets/app-icon/pdfcraft.svg, referenced via an SVG image element, not copied)" licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" +licence_file = "assets/app-icon/LICENSE.txt" kind = "image" -usage = "README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "0a309ba73bcfccbe0106824b55fc347cc0b32293d1db68149d5eccec9c087ba1" +usage = "Finder window of the macOS DMG; rendered to background.tiff by packaging/macos/dmg/generate.py" +sha256 = "e8b9ea9d5e64b7b741c977543c1693825e77d5c4c579eeb674bf5dcd3764cd8a" [[asset]] -path = "docs/images/pdfcraft-palette.png" -title = "PdfCraft screenshot: Command palette" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" +path = "packaging/macos/dmg/background.tiff" +title = "PdfCraft macOS DMG window background (rendered)" +author = "@XusBadia" +source = "Rendered from packaging/macos/dmg/background.svg by packaging/macos/dmg/generate.py" licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" +licence_file = "assets/app-icon/LICENSE.txt" kind = "image" -usage = "README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "74867793e506c03255459e838eef0b08e485c13b7ea8a6b8de3ec16870067eda" +usage = "1x + 2x HiDPI 16-colour palette TIFF copied into the macOS DMG by packaging/macos/package.sh; includes the app icon and the free LittleCMS built-in sRGB profile" +sha256 = "f46881724a6621f3686a612a79dbdce4f7dbe9e2025610e44c9a094341334c2c" [[asset]] -path = "docs/images/pdfcraft-properties.png" -title = "PdfCraft screenshot: Document properties" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" +path = "crates/sign/tests/data/x509-rsa-sha1.pdf" +title = "One-page PDF with a legacy adbe.x509.rsa_sha1 signature by the RSA test key" +author = "PdfCraft contributors" +source = "Contributor-original: hand-written PDF objects; signature made with `openssl dgst -sha1 -sign` over its byte ranges (see crates/sign/tests/data/README.md)" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "86f293543b299fa1665db999a68978138f8d61a4082d7c5b5025498e188da459" +kind = "document" +usage = "Signature validation tests (crates/sign/tests/pdf.rs): the legacy adbe.x509.rsa_sha1 format" +sha256 = "b77bfb21166f4bd043597e45a1ea28b9d9f4ba6df0142b3a0fc8b7f8e0fc111b" [[asset]] -path = "docs/images/pdfcraft-scripts.png" -title = "PdfCraft screenshot: Scripts of the world" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" +path = "docs/images/linkco-home-dashboard.png" +title = "Linkco PDF Editor screenshot: Home dashboard and Recommended Tools" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." source = "this repository" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "image" -usage = "README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "0dde8ed5a14dee7396379963adff517bd249c7dd0fe494c389b612e643584b15" +usage = "README: Home dashboard and Recommended Tools screenshot" +sha256 = "7b9f99fa3a0608abcb4da5e1e0e09d457955d7515b696a4f99b06094a4ae8d5f" [[asset]] -path = "docs/images/pdfcraft-split.png" -title = "PdfCraft screenshot: Split dialog" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" +path = "docs/images/linkco-organize-pages.png" +title = "Linkco PDF Editor screenshot: Organize pages view" +author = "Al Rawabet Commercial Services & Contracting Company W.L.L." source = "this repository" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "image" -usage = "README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "bf31e13b563ead564af968c5fae8d1c07b91ee38867d0cf1aae9e0582efc2fe5" +usage = "README: Organize pages screenshot" +sha256 = "a948a28af19970e6a7071c99ba606093012bb9c990c21147b5e935e1371b9231" -[[asset]] -path = "docs/images/pdfcraft-tools.png" -title = "PdfCraft screenshot: All tools" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: tool catalogue. Shows PdfCraft UI, Lucide icons, the showcase PDF built from the [[fetched]] OFL fonts, and the ArtCraft mark (Storyteller trademark from docs/brand/, not covered by this licence)" -sha256 = "61731a921902e285d40826d401f1ef25624dabb8c8ac1f8f0c09c1292a17ee1a" +[[bundled]] +crate = "epaint_default_fonts" +version = "0.36.2" +path = "fonts/Ubuntu-Light.ttf" +title = "Ubuntu Light" +author = "Canonical Ltd. / Dalton Maag" +source = "https://design.ubuntu.com/font" +licence = "Ubuntu-font-1.0" +kind = "font" +usage = "egui fallback fonts (eframe feature default_fonts)" +sha256 = "80307b8da7649aa4ee4d484b232140e3ce1ec0ca093073d3c53c8f5a5ced7a70" -[[asset]] -path = "docs/images/pdfcraft-twoup.png" -title = "PdfCraft screenshot: Two-up reading" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "image" -usage = "README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "a72ed1b84c827e3aa1dd3282d857b4742f02d8ff23fc39b62115c840ebad14b4" +[[bundled]] +crate = "epaint_default_fonts" +version = "0.36.2" +path = "fonts/Hack-Regular.ttf" +title = "Hack Regular" +author = "Source Foundry Authors (derived from Bitstream Vera / DejaVu)" +source = "https://github.com/source-foundry/Hack" +licence = "MIT AND Bitstream-Vera" +kind = "font" +usage = "egui fallback fonts (eframe feature default_fonts)" +sha256 = "15f55cc0c85a2988d2b4b3a8cdb5d77fdfbaf319e1bb5309d725db9818fb7125" -[[asset]] -path = "docs/images/pdfcraft-viewer.png" -title = "PdfCraft screenshot: Viewer with comments" -author = "PdfCraft contributors (generated by `cargo xtask screenshots`)" -source = "this repository" +[[bundled]] +crate = "epaint_default_fonts" +version = "0.36.2" +path = "fonts/NotoEmoji-Regular.ttf" +title = "Noto Emoji (monochrome)" +author = "Google Inc." +source = "https://github.com/googlefonts/noto-emoji" +licence = "OFL-1.1" +kind = "font" +usage = "egui fallback fonts (eframe feature default_fonts)" +sha256 = "415dc6290378574135b64c808dc640c1df7531973290c4970c51fdeb849cb0c5" + +[[bundled]] +crate = "epaint_default_fonts" +version = "0.36.2" +path = "fonts/emoji-icon-font.ttf" +title = "emoji-icon-font" +author = "John Slegers" +source = "https://github.com/jslegers/emoji-icon-font" +licence = "MIT" +kind = "font" +usage = "egui fallback fonts (eframe feature default_fonts)" +sha256 = "f426bec371f484646d002717e2c555a95cd5145e635d83a48bbef83f3abf18ca" + +[[bundled]] +crate = "hayro-cmap" +version = "0.1.0" +path = "assets/cmaps.brotli" +title = "Adobe CMap resources (predefined CJK CMaps)" +author = "Adobe" +source = "https://github.com/adobe-type-tools/cmap-resources (via hayro-cmap)" +licence = "BSD-3-Clause" +kind = "data" +usage = "Character-code mapping tables required to read CJK PDFs. Non-visual data, allowed by AGENTS.md §1.1" +sha256 = "ddf37af521d904d5646c2fc37b2b7e912dc1b56f0d210190b61f598154758e46" +adobe_data = true + +[[bundled]] +crate = "hayro-interpret" +version = "0.7.0" +path = "src/font/generated/metrics.rs" +title = "Standard-14 font metrics and encodings (as Rust tables)" +author = "Adobe (Core 14 AFM metrics, PDF specification encodings); tables by The Hayro Authors" +source = "ISO 32000-2 Annex D; Adobe Core14 AFM files (via vendored hayro-interpret)" licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "image" -usage = "README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts" -sha256 = "ecd261028d8837f7f7c013dd796d81ca7e89643bcfcbad3ab9fbfbe87ded04e3" +kind = "data" +usage = "Glyph widths and encodings for non-embedded standard fonts. Non-visual data, allowed by AGENTS.md §1.1" +sha256 = "2ec9e608573eda459de1e1d9bda3bb494315e36bee885acc88912a11fe0caa41" +adobe_data = true -[[asset]] -path = "assets/icons/pin.svg" -title = "Lucide icon \"pin\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pin.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "d28d42dd90e0ed601fb7120b6e0b98218289da8fc7bf41fac5ca83aeffd0ae32" +[[fetched]] +file = "PlayfairDisplay[wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/PlayfairDisplay%5Bwght%5D.ttf" +title = "Playfair Display" +author = "The Playfair Display Project Authors (Claus Eggers Sørensen)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/OFL.txt" +licence_sha256 = "566be814f8e96e93dfa16101331557eb6b5467e9e03f627c0910fe93ca12300e" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "c40f2293766a503bc70cce9e512ef844a4ccb7cbcde792fe2ea31d191917d8d6" -[[asset]] -path = "assets/icons/move-right.svg" -title = "Lucide icon \"move-right\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-right.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "d4586a7c7aea911762604211e3624b3436b998d1343b0b29162b3eddf9e6ab81" +[[fetched]] +file = "PlayfairDisplay-Italic[wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/PlayfairDisplay-Italic%5Bwght%5D.ttf" +title = "Playfair Display Italic" +author = "The Playfair Display Project Authors (Claus Eggers Sørensen)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/playfairdisplay/OFL.txt" +licence_sha256 = "566be814f8e96e93dfa16101331557eb6b5467e9e03f627c0910fe93ca12300e" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "a5e26dc5e2e77fb2803a0bf02fd4f81ee136ec8dea863ccdb0c59a263b21378b" -[[asset]] -path = "assets/icons/reply.svg" -title = "Lucide icon \"reply\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/reply.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "f6161386877fb29e058c85ac76f1793fb43f6fcf5144b21ef3f36a367cb41e94" +[[fetched]] +file = "EBGaramond[wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/EBGaramond%5Bwght%5D.ttf" +title = "EB Garamond" +author = "The EB Garamond Project Authors (Georg Duffner, Octavio Pardo)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/OFL.txt" +licence_sha256 = "0985066662eb755ed3683ae5482a81a9195b49ce3f7e165cc2388b3dbece7dd7" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "ef9512f92f6d579e5dc75af59a5a4b1b8b47d2eda89e00b954d44520e5369027" -[[asset]] -path = "assets/icons/thumbs-up.svg" -title = "Lucide icon \"thumbs-up\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/thumbs-up.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "e30b1dc9b4f1d56fa935ee55a4a2c9dad0eaeaffa6603085a1d3f8d5c22f60a3" +[[fetched]] +file = "EBGaramond-Italic[wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/EBGaramond-Italic%5Bwght%5D.ttf" +title = "EB Garamond Italic" +author = "The EB Garamond Project Authors (Georg Duffner, Octavio Pardo)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/ebgaramond/OFL.txt" +licence_sha256 = "0985066662eb755ed3683ae5482a81a9195b49ce3f7e165cc2388b3dbece7dd7" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "bba2c4499c93c9612b90b9825d32b07da52fce2fe57562a1eb6b833553f93c4e" -[[asset]] -path = "assets/icons/thumbs-down.svg" -title = "Lucide icon \"thumbs-down\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/thumbs-down.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "283a01b7798806a6b9ffd19f4c449e72a08ef860281fa0d33b584b52590e7240" +[[fetched]] +file = "GreatVibes-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/greatvibes/GreatVibes-Regular.ttf" +title = "Great Vibes" +author = "The Great Vibes Pro Project Authors (TypeSETit)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/greatvibes" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/greatvibes/OFL.txt" +licence_sha256 = "61093a21f5e63dedf54222b3c09997e54c0fe43e3851d21386e02ddcbc246d49" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "8d509802186f1b51572531ecf313e8098f9a5bfdfaca93f0c9b34467f9982d15" + +[[fetched]] +file = "STIXTwoMath-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/stixtwomath/STIXTwoMath-Regular.ttf" +title = "STIX Two Math" +author = "The STIX Fonts Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/stixtwomath" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/stixtwomath/OFL.txt" +licence_sha256 = "0c8825913b60d858aacdb33c4ca6660a7d64b0d6464702efbb19313f5765861a" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "562551b15b836e6e01d1b7350909baf3c8c8d83260c1190fbf4544333e6936de" + +[[fetched]] +file = "Amiri-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/amiri/Amiri-Regular.ttf" +title = "Amiri" +author = "The Amiri Project Authors (Khaled Hosny)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/amiri" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/amiri/OFL.txt" +licence_sha256 = "72de68e5954f4fdd24702292ef5a32f003ca960ec9330dc86e5eefb5dffb9b22" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "ab391c4147d054c48976e98322ad0eefe1427aa0e0502a12a4c75d80a70cfcd7" + +[[fetched]] +file = "NotoSansHebrew[wdth,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanshebrew/NotoSansHebrew%5Bwdth%2Cwght%5D.ttf" +title = "Noto Sans Hebrew" +author = "The Noto Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanshebrew" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanshebrew/OFL.txt" +licence_sha256 = "9b9fe028b5ba74d231659a1bbaf0ed09b11e759d1ca6a070999e16d151616b47" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "7ef36a2c3593758cdb622e1bdef4f84523e92fbc3ccc667438dd80ff54c2de88" -[[asset]] -path = "assets/icons/message-square-plus.svg" -title = "Lucide icon \"message-square-plus\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-plus.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "5e9d80429d9b219c98402a0d4f3194d2a0cbfe0c41dd42f46771a4d7e1c563e8" +[[fetched]] +file = "NotoSansDevanagari[wdth,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansdevanagari/NotoSansDevanagari%5Bwdth%2Cwght%5D.ttf" +title = "Noto Sans Devanagari" +author = "The Noto Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansdevanagari" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansdevanagari/OFL.txt" +licence_sha256 = "a216f6f8d85c7228093e0ee5e258d9d377e6671f68acb4db1930b29583d0f331" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "14ec4af41f27482216d1c2229f417ff9b1425e1babb014e57d1d40d03229853e" -[[asset]] -path = "assets/icons/circle-x.svg" -title = "Lucide icon \"circle-x\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/circle-x.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "ef1fec17d88794ba6c34c5cf63bdadbd234b3d4dffbcc3d55468b47e3f398472" +[[fetched]] +file = "NotoSansThai[wdth,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansthai/NotoSansThai%5Bwdth%2Cwght%5D.ttf" +title = "Noto Sans Thai" +author = "The Noto Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansthai" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansthai/OFL.txt" +licence_sha256 = "2e98fd23a52d253db8612cd5942c8f2ff4111b21d2367050fdca91d8ccc374a0" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "5a1c559bb539583c8a1fd99d1c5b9491e5e14478c9cd2bd0970d5c3096cc9ef8" -[[asset]] -path = "crates/ui-egui/tests/data/form.pdf" -title = "One-page AcroForm test fixture (text, check box, radio group, combo box)" -author = "PdfCraft contributors" -source = "Contributor-original: hand-written PDF objects, no third-party content" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "document" -usage = "Form-filling UI tests (crates/ui-egui/tests/forms.rs, commands.rs)" -sha256 = "c6f8b656e225101129aa36bd5467adc8dba16730915f19caca17f6a546d0b040" +[[fetched]] +file = "NotoSansArmenian[wdth,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansarmenian/NotoSansArmenian%5Bwdth%2Cwght%5D.ttf" +title = "Noto Sans Armenian" +author = "The Noto Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansarmenian" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansarmenian/OFL.txt" +licence_sha256 = "0468358b316f69f405b55cadf8a8314e16e3610b8feaad96772bd5d968112d02" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "0870908d8318435a5daf1cd280ae15063f990cd9ad60f3e94c734ce9e1ffef71" -[[asset]] -path = "assets/icons/pentagon.svg" -title = "Lucide icon \"pentagon\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pentagon.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "55a9c2b2531928957c23e7695ccd39b096a3b3f2a5ef3e66b3ad970742e20f26" +[[fetched]] +file = "NotoSansGeorgian[wdth,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansgeorgian/NotoSansGeorgian%5Bwdth%2Cwght%5D.ttf" +title = "Noto Sans Georgian" +author = "The Noto Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansgeorgian" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosansgeorgian/OFL.txt" +licence_sha256 = "8c02263c5d73d40544f9ed91e30c4e947407057a3cc430d7b786189aeceff6df" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "dc591156f36842d38996c4a7a17fee9bb58e45da3e2cac7a31b7d33de700adb9" -[[asset]] -path = "assets/icons/message-square-quote.svg" -title = "Lucide icon \"message-square-quote\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-quote.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "69a76b4cd352dbdea61c63ed1e8d1e02083ee1773b3ced2a1c8cdf8c90fb2055" +[[fetched]] +file = "NotoSansTamil[wdth,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanstamil/NotoSansTamil%5Bwdth%2Cwght%5D.ttf" +title = "Noto Sans Tamil" +author = "The Noto Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanstamil" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notosanstamil/OFL.txt" +licence_sha256 = "f8ff8ce7d0a81bf8d5e121c635ef027250c531f2fd37d5988b8dd6e45f19d7f1" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "aa3a9b321f4b0bb2c40203ffbde9af89713227866e0e13f76e5b9eeea727cf88" -[[asset]] -path = "crates/sign/tests/data/openssl-signed.pdf" -title = "One-page PDF signed with OpenSSL CMS (adbe.pkcs7.detached) by the RSA test key" -author = "PdfCraft contributors" -source = "Contributor-original: hand-written PDF objects; signature made with `openssl cms -sign` over its byte ranges (see crates/sign/tests/data/README.md)" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "document" -usage = "Signature validation tests (crates/sign/tests/pdf.rs): a signature PdfCraft did not make" -sha256 = "8b91c3b4e39c4a31717a0dd0685bd7d0468671df32aee5b9818d44dc72c2bc3c" +[[fetched]] +file = "CharisSIL-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/charissil/CharisSIL-Regular.ttf" +title = "Charis SIL" +author = "SIL International" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/charissil" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/charissil/OFL.txt" +licence_sha256 = "0acda775b4dedaf980821f590206a692779ee495170018ee2b9caf1c50fc136a" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "346337374aa347d64ee015b26d441f1970d8631914e2f3941b00e1c4761e28c5" -[[asset]] -path = "assets/icons/clipboard-paste.svg" -title = "Lucide icon \"clipboard-paste\"" -author = "Lucide Contributors (portions Cole Bemis, Feather)" -source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/clipboard-paste.svg)" -licence = "ISC" -licence_file = "assets/icons/LICENSE-lucide.txt" -kind = "icon" -usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs" -sha256 = "631d24bde604be36b2dcf3b6f86ddf6026879cdcd272c0dfe37ab0cc6b341fda" +[[fetched]] +file = "ZCOOLXiaoWei-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/zcoolxiaowei/ZCOOLXiaoWei-Regular.ttf" +title = "ZCOOL XiaoWei" +author = "The ZCOOL XiaoWei Project Authors" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/zcoolxiaowei" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/zcoolxiaowei/OFL.txt" +licence_sha256 = "a094514ca57cf8f9c5e8d8d1adab5d8cd3a377297ff016f9df2c05b3ecd77f0a" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "a42b620140f493db42f741351dfbf343c0936d58588ee8004b8b2a218d997ff1" -[[asset]] -path = "assets/fonts/DancingScript.ttf" -title = "Dancing Script (variable)" -author = "The Dancing Script Project Authors (Pablo Impallari)" -source = "https://github.com/google/fonts/blob/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/dancingscript/DancingScript%5Bwght%5D.ttf" +[[fetched]] +file = "ShipporiMincho-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/shipporimincho/ShipporiMincho-Regular.ttf" +title = "Shippori Mincho" +author = "The Shippori Mincho Project Authors (FONTDASU)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/shipporimincho" licence = "OFL-1.1" -licence_file = "assets/fonts/OFL-DancingScript.txt" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/shipporimincho/OFL.txt" +licence_sha256 = "41fba056279be5f45ff9a99e44b7b53897b42732f5806d8e666e0ab49ac6bd38" kind = "font" -usage = "Fill & Sign typed signatures and initials: the typed name's glyph outlines, drawn as filled paths (the font file itself is not embedded in PDFs)" -sha256 = "21808625578fe8d8cd10cb684be546dca077b27cd03a53a2f1ec11dc743c924c" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "769b5269f0f9bc6534b352c0e6bd856a566e03ff788f107191c2d835863570b2" -[[asset]] -path = "packaging/macos/dmg/background.svg" -title = "PdfCraft macOS DMG window background" -author = "@XusBadia" -source = "Original work for this repository, derived from the PdfCraft app icon (assets/app-icon/pdfcraft.svg, referenced via an SVG image element, not copied)" -licence = "MIT OR Apache-2.0" -licence_file = "assets/app-icon/LICENSE.txt" -kind = "image" -usage = "Finder window of the macOS DMG; rendered to background.tiff by packaging/macos/dmg/generate.py" -sha256 = "e8b9ea9d5e64b7b741c977543c1693825e77d5c4c579eeb674bf5dcd3764cd8a" +[[fetched]] +file = "GowunBatang-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/gowunbatang/GowunBatang-Regular.ttf" +title = "Gowun Batang" +author = "The Gowun Batang Project Authors (Yanghee Ryu)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/gowunbatang" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/gowunbatang/OFL.txt" +licence_sha256 = "49a57cc769fa9affd6eefb9070a61e3d3f6b757c97cafb15848bc6d1c81acc78" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "466c593e7147412e748af4856d5ad14709b5a860bdf62b9c2546f2c5874e9849" +[[fetched]] +file = "NotoColorEmoji-Regular.ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notocoloremoji/NotoColorEmoji-Regular.ttf" +title = "Noto Color Emoji" +author = "Google Inc." +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notocoloremoji" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notocoloremoji/OFL.txt" +licence_sha256 = "ac564676d10054a8445923dfc2dfb13c042d97888bd27c1b6ec6dfe89a9d8d62" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "4d82a18d8d95f60ba883ce242bbadbf84a576e987745dd7ba38d71c67cff2d73" -[[asset]] -path = "packaging/macos/dmg/background.tiff" -title = "PdfCraft macOS DMG window background (rendered)" -author = "@XusBadia" -source = "Rendered from packaging/macos/dmg/background.svg by packaging/macos/dmg/generate.py" -licence = "MIT OR Apache-2.0" -licence_file = "assets/app-icon/LICENSE.txt" -kind = "image" -usage = "1x + 2x HiDPI 16-colour palette TIFF copied into the macOS DMG by packaging/macos/package.sh; includes the app icon and the free LittleCMS built-in sRGB profile" -sha256 = "f46881724a6621f3686a612a79dbdce4f7dbe9e2025610e44c9a094341334c2c" +[[fetched]] +file = "Inter[opsz,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/Inter%5Bopsz%2Cwght%5D.ttf" +title = "Inter (variable)" +author = "The Inter Project Authors (Rasmus Andersson)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/OFL.txt" +licence_sha256 = "5b9321a4298cfeb6b34354164a1c3afc3db114569984c502b9b35d988fd58c57" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "29160a80ff49ddcab2c97711247e08b1fab27a484a329ce8b813d820dc559031" + +[[fetched]] +file = "Inter-Italic[opsz,wght].ttf" +url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/Inter-Italic%5Bopsz%2Cwght%5D.ttf" +title = "Inter Italic (variable)" +author = "The Inter Project Authors (Rasmus Andersson)" +source = "https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter" +licence = "OFL-1.1" +licence_url = "https://raw.githubusercontent.com/google/fonts/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter/OFL.txt" +licence_sha256 = "5b9321a4298cfeb6b34354164a1c3afc3db114569984c502b9b35d988fd58c57" +kind = "font" +usage = "Showcase PDF (cargo xtask demo-pdf)" +sha256 = "acd98e64795781b2058f07b18475e0ecee2a0fe2b42a49e2f9e37d0d6bf66ce6" [[fetched]] file = "text-detection.rten" @@ -3274,14 +3075,3 @@ licence = "OFL-1.1" attribution = "https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md" kind = "font" usage = "Japanese fallback in the interface (BIZ UDPGothic first) and Japanese glyphs in edited PDF text (Shippori Mincho); Arabic interface text, file names and document titles (Noto Sans Arabic); the web build embeds only BIZ UDPGothic Regular and Noto Sans Arabic. The checkout also holds Noto Sans CJK SC, which crates/fonts/build.rs never embeds (AGENTS.md §1.1)" - -[[asset]] -path = "crates/sign/tests/data/x509-rsa-sha1.pdf" -title = "One-page PDF with a legacy adbe.x509.rsa_sha1 signature by the RSA test key" -author = "PdfCraft contributors" -source = "Contributor-original: hand-written PDF objects; signature made with `openssl dgst -sha1 -sign` over its byte ranges (see crates/sign/tests/data/README.md)" -licence = "MIT OR Apache-2.0" -licence_file = "LICENSE-MIT" -kind = "document" -usage = "Signature validation tests (crates/sign/tests/pdf.rs): the legacy adbe.x509.rsa_sha1 format" -sha256 = "b77bfb21166f4bd043597e45a1ea28b9d9f4ba6df0142b3a0fc8b7f8e0fc111b" diff --git a/Cargo.lock b/Cargo.lock index d42992b9ce..3a5e12caa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3552,7 +3552,7 @@ dependencies = [ [[package]] name = "pdfcraft" -version = "0.6.0" +version = "1.0.0" dependencies = [ "eframe", "egui", @@ -3570,7 +3570,7 @@ dependencies = [ [[package]] name = "pdfcraft-a11y" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-content", "pdfcraft-cos", @@ -3581,7 +3581,7 @@ dependencies = [ [[package]] name = "pdfcraft-annot" -version = "0.6.0" +version = "1.0.0" dependencies = [ "hayro-syntax", "pdfcraft-cos", @@ -3592,7 +3592,7 @@ dependencies = [ [[package]] name = "pdfcraft-automation" -version = "0.6.0" +version = "1.0.0" dependencies = [ "base64 0.22.1", "image", @@ -3609,7 +3609,7 @@ dependencies = [ [[package]] name = "pdfcraft-cli" -version = "0.6.0" +version = "1.0.0" dependencies = [ "base64 0.22.1", "pdfcraft-automation", @@ -3623,18 +3623,18 @@ dependencies = [ [[package]] name = "pdfcraft-compare" -version = "0.6.0" +version = "1.0.0" [[package]] name = "pdfcraft-content" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-cos", ] [[package]] name = "pdfcraft-cos" -version = "0.6.0" +version = "1.0.0" dependencies = [ "hayro-syntax", "pdfcraft-crypt", @@ -3646,7 +3646,7 @@ dependencies = [ [[package]] name = "pdfcraft-create" -version = "0.6.0" +version = "1.0.0" dependencies = [ "encoding_rs", "hayro-syntax", @@ -3661,7 +3661,7 @@ dependencies = [ [[package]] name = "pdfcraft-crypt" -version = "0.6.0" +version = "1.0.0" dependencies = [ "aes", "md-5", @@ -3673,7 +3673,7 @@ dependencies = [ [[package]] name = "pdfcraft-edit" -version = "0.6.0" +version = "1.0.0" dependencies = [ "hayro-syntax", "pdfcraft-annot", @@ -3687,7 +3687,7 @@ dependencies = [ [[package]] name = "pdfcraft-engine" -version = "0.6.0" +version = "1.0.0" dependencies = [ "chrono", "icu_properties", @@ -3722,14 +3722,14 @@ dependencies = [ [[package]] name = "pdfcraft-export" -version = "0.6.0" +version = "1.0.0" dependencies = [ "flate2", ] [[package]] name = "pdfcraft-filters" -version = "0.6.0" +version = "1.0.0" dependencies = [ "flate2", "proptest", @@ -3739,7 +3739,7 @@ dependencies = [ [[package]] name = "pdfcraft-fonts" -version = "0.6.0" +version = "1.0.0" dependencies = [ "harfrust", "pdfcraft-cos", @@ -3748,7 +3748,7 @@ dependencies = [ [[package]] name = "pdfcraft-forms" -version = "0.6.0" +version = "1.0.0" dependencies = [ "hayro-syntax", "pdfcraft-content", @@ -3760,18 +3760,18 @@ dependencies = [ [[package]] name = "pdfcraft-geom" -version = "0.6.0" +version = "1.0.0" [[package]] name = "pdfcraft-js" -version = "0.6.0" +version = "1.0.0" dependencies = [ "boa_engine", ] [[package]] name = "pdfcraft-measure" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-annot", "pdfcraft-content", @@ -3783,14 +3783,14 @@ dependencies = [ [[package]] name = "pdfcraft-model" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-cos", ] [[package]] name = "pdfcraft-ocr" -version = "0.6.0" +version = "1.0.0" dependencies = [ "ocrs", "pdfcraft-fonts", @@ -3800,7 +3800,7 @@ dependencies = [ [[package]] name = "pdfcraft-optimize" -version = "0.6.0" +version = "1.0.0" dependencies = [ "image", "pdfcraft-annot", @@ -3813,7 +3813,7 @@ dependencies = [ [[package]] name = "pdfcraft-organize" -version = "0.6.0" +version = "1.0.0" dependencies = [ "hayro-syntax", "pdfcraft-content", @@ -3823,14 +3823,14 @@ dependencies = [ [[package]] name = "pdfcraft-platform" -version = "0.6.0" +version = "1.0.0" dependencies = [ "zbus", ] [[package]] name = "pdfcraft-preflight" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-cos", "pdfcraft-model", @@ -3838,7 +3838,7 @@ dependencies = [ [[package]] name = "pdfcraft-print" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-content", "pdfcraft-cos", @@ -3848,7 +3848,7 @@ dependencies = [ [[package]] name = "pdfcraft-redact" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-annot", "pdfcraft-content", @@ -3862,7 +3862,7 @@ dependencies = [ [[package]] name = "pdfcraft-render" -version = "0.6.0" +version = "1.0.0" dependencies = [ "bytemuck", "flate2", @@ -3880,7 +3880,7 @@ dependencies = [ [[package]] name = "pdfcraft-sign" -version = "0.6.0" +version = "1.0.0" dependencies = [ "aes", "aws-lc-rs", @@ -3914,7 +3914,7 @@ dependencies = [ [[package]] name = "pdfcraft-ui-egui" -version = "0.6.0" +version = "1.0.0" dependencies = [ "arboard", "base64 0.22.1", @@ -3954,7 +3954,7 @@ dependencies = [ [[package]] name = "pdfcraft-web" -version = "0.6.0" +version = "1.0.0" dependencies = [ "eframe", "egui", @@ -3966,7 +3966,7 @@ dependencies = [ [[package]] name = "pdfcraft-xfa" -version = "0.6.0" +version = "1.0.0" dependencies = [ "base64 0.22.1", "image", @@ -3980,7 +3980,7 @@ dependencies = [ [[package]] name = "pdfcraft-xfdf" -version = "0.6.0" +version = "1.0.0" dependencies = [ "pdfcraft-annot", "pdfcraft-cos", diff --git a/Cargo.toml b/Cargo.toml index 0214a7bf4f..10dc456c22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ exclude = ["vendor"] default-members = ["crates/*", "apps/pdfcraft", "apps/pdfcraft-cli", "xtask"] [workspace.package] -version = "0.6.0" +version = "1.0.0" edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.90" @@ -15,36 +15,36 @@ repository = "https://github.com/storytold/pdfcraft" # Shared frontend components; engines remain independent of egui. craft-ui = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "5c874d51eeb3de70e735c8ce87a59a7dedd47675", features = ["serde"] } # internal -pdfcraft-geom = { path = "crates/geom", version = "0.6.0" } -pdfcraft-filters = { path = "crates/filters", version = "0.6.0" } -pdfcraft-cos = { path = "crates/cos", version = "0.6.0" } -pdfcraft-crypt = { path = "crates/crypt", version = "0.6.0" } -pdfcraft-organize = { path = "crates/organize", version = "0.6.0" } -pdfcraft-measure = { path = "crates/measure", version = "0.6.0" } -pdfcraft-annot = { path = "crates/annot", version = "0.6.0" } -pdfcraft-fonts = { path = "crates/fonts", version = "0.6.0" } -pdfcraft-model = { path = "crates/model", version = "0.6.0" } -pdfcraft-content = { path = "crates/content", version = "0.6.0" } -pdfcraft-redact = { path = "crates/redact", version = "0.6.0" } -pdfcraft-print = { path = "crates/print", version = "0.6.0" } -pdfcraft-xfdf = { path = "crates/xfdf", version = "0.6.0" } -pdfcraft-sign = { path = "crates/sign", version = "0.6.0" } -pdfcraft-optimize = { path = "crates/optimize", version = "0.6.0" } -pdfcraft-a11y = { path = "crates/a11y", version = "0.6.0" } -pdfcraft-ocr = { path = "crates/ocr", version = "0.6.0" } -pdfcraft-js = { path = "crates/js", version = "0.6.0" } -pdfcraft-compare = { path = "crates/compare", version = "0.6.0" } -pdfcraft-preflight = { path = "crates/preflight", version = "0.6.0" } -pdfcraft-export = { path = "crates/export", version = "0.6.0" } -pdfcraft-edit = { path = "crates/edit", version = "0.6.0" } -pdfcraft-create = { path = "crates/create", version = "0.6.0" } -pdfcraft-forms = { path = "crates/forms", version = "0.6.0" } -pdfcraft-xfa = { path = "crates/xfa", version = "0.6.0" } -pdfcraft-render = { path = "crates/render", version = "0.6.0" } -pdfcraft-engine = { path = "crates/engine", version = "0.6.0" } -pdfcraft-platform = { path = "crates/platform", version = "0.6.0" } -pdfcraft-ui-egui = { path = "crates/ui-egui", version = "0.6.0" } -pdfcraft-automation = { path = "crates/automation", version = "0.6.0", default-features = false } +pdfcraft-geom = { path = "crates/geom", version = "1.0.0" } +pdfcraft-filters = { path = "crates/filters", version = "1.0.0" } +pdfcraft-cos = { path = "crates/cos", version = "1.0.0" } +pdfcraft-crypt = { path = "crates/crypt", version = "1.0.0" } +pdfcraft-organize = { path = "crates/organize", version = "1.0.0" } +pdfcraft-measure = { path = "crates/measure", version = "1.0.0" } +pdfcraft-annot = { path = "crates/annot", version = "1.0.0" } +pdfcraft-fonts = { path = "crates/fonts", version = "1.0.0" } +pdfcraft-model = { path = "crates/model", version = "1.0.0" } +pdfcraft-content = { path = "crates/content", version = "1.0.0" } +pdfcraft-redact = { path = "crates/redact", version = "1.0.0" } +pdfcraft-print = { path = "crates/print", version = "1.0.0" } +pdfcraft-xfdf = { path = "crates/xfdf", version = "1.0.0" } +pdfcraft-sign = { path = "crates/sign", version = "1.0.0" } +pdfcraft-optimize = { path = "crates/optimize", version = "1.0.0" } +pdfcraft-a11y = { path = "crates/a11y", version = "1.0.0" } +pdfcraft-ocr = { path = "crates/ocr", version = "1.0.0" } +pdfcraft-js = { path = "crates/js", version = "1.0.0" } +pdfcraft-compare = { path = "crates/compare", version = "1.0.0" } +pdfcraft-preflight = { path = "crates/preflight", version = "1.0.0" } +pdfcraft-export = { path = "crates/export", version = "1.0.0" } +pdfcraft-edit = { path = "crates/edit", version = "1.0.0" } +pdfcraft-create = { path = "crates/create", version = "1.0.0" } +pdfcraft-forms = { path = "crates/forms", version = "1.0.0" } +pdfcraft-xfa = { path = "crates/xfa", version = "1.0.0" } +pdfcraft-render = { path = "crates/render", version = "1.0.0" } +pdfcraft-engine = { path = "crates/engine", version = "1.0.0" } +pdfcraft-platform = { path = "crates/platform", version = "1.0.0" } +pdfcraft-ui-egui = { path = "crates/ui-egui", version = "1.0.0" } +pdfcraft-automation = { path = "crates/automation", version = "1.0.0", default-features = false } # pdf hayro = "0.7.1" diff --git a/NOTICE b/NOTICE index 7218477937..4c746d51e3 100644 --- a/NOTICE +++ b/NOTICE @@ -1,20 +1,26 @@ -PdfCraft -Copyright (c) 2026 ArtCraft Team and the PdfCraft contributors. -Licensed under the MIT License or the Apache License, Version 2.0, at your option -(LICENSE-MIT, LICENSE-APACHE). +Linkco PDF Editor +Copyright © Al Rawabet Commercial Services & Contracting Company W.L.L. -The ArtCraft name, wordmark and logos in docs/brand/ are trademarks of the ArtCraft Team. They are -not open source and are not covered by the license above; their terms are in -docs/brand/LICENSE-brand.txt. +Based on PdfCraft (Copyright 2026 ArtCraft Team, Learning Machines LLC and the PdfCraft +contributors), used under the MIT License or the Apache License, Version 2.0. + +This product is dual-licensed under the MIT License (LICENSE-MIT) and the +Apache License, Version 2.0 (LICENSE-APACHE), at your option. + +Application icons (assets/app-icon/pdfcraft.svg, pdfcraft-small.svg, pdfcraft-1024.png, +pdfcraft.icns, pdfcraft.ico and hicolor/) are original Linkco PDF Editor brand assets licensed +under MIT OR Apache-2.0 (assets/app-icon/LICENSE.txt). The ArtCraft name, wordmark and logos are +trademarks of the ArtCraft Team and are not used by this product. Third-party material -This product bundles third-party material under its own licenses, listed below. The per-file +Linkco PDF Editor bundles third-party material under its own licenses, listed below. The per-file list (author, source, license) is in ATTRIBUTION.md. - Lucide icons (assets/icons/*.svg) — ISC License. See assets/icons/LICENSE-lucide.txt. The Windows PDF file icon (assets/app-icon/pdfcraft-document.svg and .ico) adapts Lucide's - file-text outline and combines it with contributor-original artwork. See + file-text outline and combines it with contributor-original artwork, recoloured to the Linkco + palette. See assets/app-icon/LICENSE-document.txt (ISC AND (MIT OR Apache-2.0)), packaged as LICENSE-document.txt beside the Windows executables. - Inter typeface (assets/fonts/Inter-*.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-Inter.txt. diff --git a/README.md b/README.md index 555eae3bd1..81bbfa714e 100644 --- a/README.md +++ b/README.md @@ -1,566 +1,354 @@

- - - - ArtCraft - - + Linkco PDF Editor logo

- -

PdfCraft

- -

- The PDF workbench; an open-source, clean-room reimplementation of Adobe Acrobat, rebuilt in pure Rust.
- Read, organize, combine, split and secure PDFs in a fast, native app, written in Rust from the ground up.
- macOS · Windows · Linux · FreeBSD · the web -

- -

- License: MIT OR Apache-2.0 - Written in Rust - Platforms: macOS, Windows, Linux, FreeBSD, web - No account, no telemetry -

- -

- Join the ArtCraft community on Discord -

+

Linkco PDF Editor

- PdfCraft on getartcraft.com · - ArtCraft · - All Crafting Apps -

- -
- -

- PdfCraft with the PdfCraft Showcase cover page open, the All tools panel on the left and 20 threaded comments on the right -
- The PdfCraft Showcase, a 13-page specimen PDF, open with the All tools panel and threaded comments. -

- -> [!NOTE] -> **ArtCraft is a community of artists from all walks of life.** Digital, generative, music, -> games — if you make things, you're one of us. **[Come say hi on Discord](https://discord.gg/artcraft).** - -

- Highlights · - Read · - Find · - Organize · - Combine & split · - Protect · - Forms & layers · - Everywhere · - Agents · - How it's built · - Get started · - What's next · - Downloads · - Crafting Apps + Professional PDF tools for Linkco (Al Rawabet Commercial Services & Contracting Company W.L.L.)
+ Doha, State of Qatar · C.R. No.: 32942 · ISO 9001, 14001 & 45001 Certified · www.linkco.com.qa

--- -## Community - -PdfCraft is part of [ArtCraft](https://getartcraft.com). Come say hello, get help and follow development: - -- **Discord: [discord.gg/artcraft](https://discord.gg/artcraft)**. This is the fastest way to get help and share feedback. The app has a Discord button in its title bar. -- **Web page:** [getartcraft.com/apps/pdfcraft](https://getartcraft.com/apps/pdfcraft) -- **Source:** [github.com/storytold/pdfcraft](https://github.com/storytold/pdfcraft) +## Overview -The ArtCraft name and logos in `docs/brand/` are trademarks of the ArtCraft Team and are not open source. They may be used only unmodified, and only as part of PdfCraft (see `docs/brand/LICENSE-brand.txt`). Forks and modified versions must remove them. +**Linkco PDF Editor** is a native desktop PDF reader, editor, and document processing suite developed for **Linkco** (**Al Rawabet Commercial Services and Contracting Company W.L.L.** — `www.linkco.com.qa`, Doha, State of Qatar). Written entirely in safe Rust with zero `unsafe` blocks across the workspace, it provides a fast, offline-first environment for viewing, editing, organizing, converting, signing, redacting, and validating PDF documents across engineering, contracting, facility maintenance, and commercial workflows. -## Highlights +All document rendering and editing operations execute locally on your workstation without requiring an account, cloud upload, or telemetry connection. - - - - - - -
- -### Faithful -Real-world typography: world scripts, vertical Japanese, colour emoji, gradients, soft masks and transparency. All of it renders the way the author intended. - - - -### Fearless -Every save appends your changes and leaves the original bytes untouched. Writes are atomic, undo runs deep, and nothing is lost if you close by mistake. - - - -### Yours -No account, no telemetry, no cloud. It works offline and opens instantly. The engine, CLI and app are all open source. +--- -
+## Features + +- **Document Viewing & Navigation** — Continuous, single-page, two-up, and cover-page layouts; zero-copy memory-mapped PDF stream decoding; 1:1 texel high-DPI rendering with seamless tile retention during zoom; precision-touchpad scrolling that follows the fingers 1:1; Preferences ▸ Interface size (Auto follows the desktop's text scaling); automatic OpenGL (`glow`) fallback on GPU initialization failure; Windows primary-display adapter selection; page thumbnails; searchable hierarchical bookmarks; Optional Content Group (OCG) layer controls; file attachments; article threads; session tab reopening (`Reopen last session`); `File ▸ Open Recent`; pinned Home folders; side-by-side synchronous document comparison; and dockable Tools and Inspector panels that can be grouped as tabs, split beside the PDF or floated in the window (a panel header's menu offers Float panel, Move to group and Close panel; View ▸ Reset panel layout restores the default). +- **Page Organization** — Interactive zoomable thumbnail grid (`crates/organize`) and Pages side panel for rotating, drag-reordering, deleting, extracting, duplicating, inserting (before any page or at the end), replacing, cropping, and splitting pages (by page count, file size, or top-level bookmarks), extracting pages under a chosen file name, building bookmarks from a tagged document's headings, plus a dedicated **Combine Files** tab (`page.combine`) with a page thumbnail grid where pages from every file can be rotated, removed and reordered before combining. +- **Direct Content Editing** — Multi-stream reflow-aware paragraph and line text editing (`crates/edit`), Arabic shaping (`harfrust`) and bidirectional (`unicode-bidi`) Type 3 text rendering, Cyrillic/Greek/WinAnsi and Japanese CID/katakana editing, grouped Form XObject figure selection and editing, new text blocks, image insertion and replacement, headers and footers, watermarks, backgrounds, Bates numbering, link editing, and vector object inspection. +- **Annotations & Markup** — Sticky notes, highlights, underlines, strikethroughs, squiggly lines, free-text callouts, ink drawings, stamps, polygons, polylines, rectangles, ellipses, lines, arrows, carets, redaction marks, a fill colour for rectangle, oval and polygon comments, and XFDF comment import/export. +- **Interactive Forms, XFA & E-Sign** — Full AcroForm field filling and authoring (text, checkbox, radio button, combo box, list box, push button, signature field, barcode), bulk multi-field property editing, rotated `/MK /R` widget rendering, `/Opt` export values, sandboxed `AF*` JavaScript and XFA FormCalc interpreter (`crates/xfa`), and **Fill & Sign** tools (text, checkmarks, crosses, dots, lines, localized dates, drawn/typed/image signatures with automatic white-background removal and live resize, initials, and optional flatten-on-save). +- **Digital Signatures & Certificates** — PKCS#7 / CMS and PAdES (`B-B`, `B-T`, `B-LT`, `B-LTA`) digital signature verification and signing (`crates/sign`), native Windows Certificate Store (`CNG` via `rustls-cng`) and macOS Keychain integration, BER `.p12`/PKCS#7 support, RSA/PSS/ECDSA/Ed25519 algorithms, strict X.509 chain validation, RFC 3161 `/DocTimeStamp` verification and timestamping, signing and timestamping password-encrypted documents, PIN prompts for smart cards and tokens in the Windows certificate store, signer certificates checked for document-signing key usage / EKU and unknown critical extensions, and DocMDP modification detection. +- **Security & True Redaction** — Password encryption (AES-256, AES-128, RC4) and permission enforcement, content-stream glyph and image redaction with verifiable byte removal, redaction of whole lists of words or phrases (typed or imported from a text file), U.S. FOIA and Privacy Act exemption codes as redaction overlay text, metadata scrubbing, and hidden-data sanitization. +- **Export & Conversion** — Export PDFs to Microsoft Word (`.docx` with Form XObject content, text color preservation, and 63-column table caps), PNG images, extracted embedded images (keeping their transparency), HTML web pages, Rich Text Format (`.rtf`), and plain text (`.txt`), or create PDFs from multiple files, images, plain text, HTML, or blank page templates. +- **High-Resolution Printing & Windows Print Spooler Integration** — Full imposition engine (Fit, Actual Size, Shrink, Custom Scale, Multiple pages per sheet with Cut & Stack, Saddle-Stitch Booklet, and Tiled Poster with cut marks), live high-DPI sheet preview, 150 / 300 / 600 DPI print rendering, native printer driver `Properties…` (`rundll32 printui.dll` on Windows / `lpoptions` PPD options on Unix), and 3-tier Windows Print Spooler (`Win32_Printer` / `.NET` `System.Drawing.Printing` / Registry) and CUPS (`lpstat -p`/`-e`) printer detection with default-printer and offline-status awareness. Printers are listed and jobs are rendered and spooled in the background, so the window stays responsive while a long document prints, and no console window flashes up on Windows. +- **Windows File Explorer PDF Preview Handler** — Out-of-process `IPreviewHandler` shell extension (`LinkcoPdfPreviewHandler.dll`) hosted by `prevhost.exe` that renders PDF pages directly inside the Windows 10/11 File Explorer Preview Pane with page navigation and zoom without launching the full editor. The same DLL provides first-page **PDF thumbnails** for Explorer's icon views. PDFs opened from Explorer, Outlook attachments or Open With while the editor is running open as tabs in the existing window (one instance per Windows sign-in; `--new-window` forces a separate one), and the executable declares Per-Monitor V2 DPI awareness for sharp rendering on mixed-DPI displays. +- **Scan & OCR** — Optical Character Recognition (`crates/ocr`) for single or multiple files with deskew, image preprocessing, and invisible searchable text layer (`Tr 3`) generation (OCR models bundled by `cargo xtask models` during release packaging or via `PDFCRAFT_MODELS`). +- **Measurement, Standards, Accessibility & Guided Actions** — Distance, perimeter, and area measurement tools (`crates/measure`) with vector snapping, calibration, and CSV export; PDF/A-2b and PDF/A-3b verification and conversion (`crates/preflight`); 32-rule accessibility checker, alternate-text editor, and HTML accessibility reports (`crates/a11y`); page box (`CropBox`, `BleedBox`, `TrimBox`, `ArtBox`) editing; multi-file batch automation via the Action Wizard (`crates/engine/src/actions.rs`); and 17 interface languages (English, Arabic with a right-to-left interface, Japanese, Brazilian Portuguese, Spanish, Telugu, Czech, Simplified Chinese, Traditional Chinese, French, German, Italian, Russian, Ukrainian, Bulgarian, Hungarian, and Polish), with keyboard shortcut key names shown in the interface language. --- -## Read anything, beautifully +## Recommended Tools -PdfCraft renders PDFs with care for the details that make a page feel right: kerning and ligatures, right-to-left and complex scripts, vertical CJK, colour emoji, shadings, blend modes, soft masks and optional content. +The Home dashboard provides one-click access to the core tools implemented in the workspace (`crates/ui-egui/src/home.rs`): -

- The Scripts of the World page: Arabic, Hebrew, Devanagari, Thai, Greek, Cyrillic, Chinese, Korean, IPA, Armenian, Georgian and Tamil samples, with vertical Japanese in the right margin -
- Twelve writing systems on one page, plus vertical Japanese, at 125%. -

- -- **Deep zoom stays sharp.** Large pages render in tiles, so text stays crisp at any magnification. -- **Built to survive bad files.** Every page renders in isolation and damaged documents are repaired. Across the 983-file pdf.js test corpus the result is 0 crashes. -- **Layouts for every task:** continuous, single page, two-up, view rotation, full screen and a distraction-free Read mode. -- **Light and dark themes**, both designed to be easy on the eyes for long sessions. - - - - - - - - - - -
Two facing pages in Read mode with the dark theme: the Foreword and the Setting Text chapter with its drop cap and pull quoteThe dark theme showing the Code and Images chapter, a syntax-coloured listing and a fractal image, with the comments panel open
Two-up Read mode, ready for long readingThe dark theme, with the comments panel open
- -## Find it, select it, copy it - -Search the whole document as you type, step through matches with ⌘G, and select text that comes out in the right reading order. That holds for columns, right-to-left runs and CJK too. - -## Navigate long documents - -Bookmarks, page thumbnails and the document's own page labels (i, ii, 1, 2…) keep you oriented in long documents. Search bookmark titles in the Bookmarks panel to find nested entries even when their parents are collapsed. Matches keep their ancestors for context; Clear restores the unfiltered tree without changing its expansion state. - - - - - - - - - - -
The find bar showing match 10 of 16 for the word 'type', highlighted in the Expressive Type chapter headingThe Bookmarks panel showing the nested outline of the showcase, with page labels such as Cover, i and ii, next to the Scripts of the World page
Find as you type: match 10 of 16Nested bookmarks with the document's own page labels
+| Tool | Description | Primary Commands | +| :--- | :--- | :--- | +| **Organize pages** | Page grid · Rotate · Delete | Opens the interactive page-organization grid (`organize`) | +| **Edit a PDF** | Edit text & images · Add text | Activates direct PDF content editing (`edit`) | +| **Combine files** | Merge PDFs · Reorder · Insert | Opens the Combine Files workspace (`page.combine`) | +| **Compress a PDF** | Reduce file size · Optimize PDF | Deduplicates streams, subsets fonts, and optimizes file size (`file.reduce_size`) | +| **Export a PDF** | Word · Image · HTML · Text | Exports the active document to `.docx`, `.png`, `.html`, `.rtf`, or `.txt` (`export`) | +| **Scan & OCR** | Recognize text · Searchable PDF | Runs optical character recognition to generate a searchable text layer (`ocr.recognize`) | +| **Fill & Sign** | Fill form fields · Sign document | Places text, checkmarks, dates, initials, and signatures on pages (`fill_sign`) | +| **Protect a PDF** | Password security · Sanitize | Applies password encryption, permissions, or document sanitization (`protect`) | +| **Open file** | Browse local filesystem | Opens one or more PDF documents from disk (`file.open`) | --- -## Organize pages like cards on a table +## Screenshots -Open **Organize pages** to see every page at once: -- **Select pages:** click, ⌘-click or ⇧-click. -- **Change them:** rotate, delete, insert blank pages, insert pages from another file, and move them earlier or later. -- **Undo anything:** ⌘Z, then save. +### Home Dashboard & Recommended Tools -

- The Organize pages grid with the showcase's pages as thumbnails, three of them selected, and the page toolbar above -
- Organize pages with three pages selected and the page tools in the toolbar above. -

+![Linkco PDF Editor — Home Dashboard](docs/images/linkco-home-dashboard.png) - - - - - -
+### Organize Pages View -**Undo that goes the distance.** Each change is one step in a history you can walk backwards and forwards. The Edit menu names the step ("Undo Rotate pages"), and undo still works after you save. +![Linkco PDF Editor — Organize Pages](docs/images/linkco-organize-pages.png) -**Saves you can trust:** -- *Incremental:* the original bytes stay byte-for-byte intact. -- *Atomic:* the file is written to a temporary copy, then swapped in. -- *Verified:* independently checked with qpdf. +--- -When open documents exceed the window width, scroll over the tab strip with the mouse wheel or trackpad, or use its horizontal scrollbar. Opening or switching to a document brings its tab into view. +## System Requirements -Unsaved documents carry a dot on their tab, and closing or quitting asks before anything is lost. Changes are autosaved every minute. If PdfCraft ever quits unexpectedly, it offers to recover your work the next time it opens. Encrypted documents stay encrypted on disk. +| Platform | Minimum Requirements | +| :--- | :--- | +| **Operating System** | Windows 10 / 11 (x64, x86, or ARM64), macOS 12+ (Apple Silicon or Intel), or Linux (x86_64 / aarch64 with X11 or Wayland) | +| **Processor** | 64-bit dual-core CPU (quad-core recommended for concurrent rendering and OCR) | +| **Memory** | 4 GB RAM minimum (8 GB RAM recommended for large multi-hundred-page documents) | +| **Graphics** | Direct3D 11/12, Metal, Vulkan, or OpenGL 3.3+ (automatic `wgpu` → `glow` OpenGL fallback included) | +| **Disk Space** | 120 MB for installed application binaries and bundled OCR models | +| **Build Toolchain** | Rust 1.85+ (`edition = "2024"`, validated on Rust 1.92) | -The Split document dialog over the organize view, set to one page per file and reporting that it creates 13 files from 13 pages
Split document: one page per file makes 13 files.
+--- -## Combine and split without losing a thing +## Installation -**Combine files** merges any number of PDFs into one. Each file gets a bookmark, with its own bookmarks nested underneath. +### From a Packaged Installer -**Extract** copies the pages you select into a new document. **Split** divides a document every *n* pages, or before the pages you choose. +1. Build or obtain the native installer for your platform from `dist/release/`: + - **Windows (NSIS / Self-Extracting Setup EXE):** `LinkcoPDFEditorSetup.exe` + - **Windows (MSI Package):** `LinkcoPDFEditorSetup--windows-.msi` + - **Windows (Portable ZIP):** `LinkcoPDFEditor--windows--portable.zip` (extract anywhere; `portable.txt` or `LinkcoPDFEditor.portable` beside the executable stores settings, logs, recovery files, and digital IDs in `PdfCraftData\` next to the executable instead of `%APPDATA%`) +2. Run the installer and follow the on-screen prompts. +3. Launch **Linkco PDF Editor** from the Windows Start Menu, Desktop shortcut, or by opening any `.pdf` file. -Nothing quietly disappears along the way: -- links and named destinations are rewired to the copied pages; -- form fields stay interactive; -- layers keep their on/off defaults; -- attachments come along. +### From Source -Every page of a combined document renders pixel-identical to its source. +1. Install the Rust toolchain via [rustup](https://www.rust-lang.org/tools/install). +2. Clone this repository and build the release binaries using `build.py` (or `cargo`): -```sh -pdfcraft-cli combine report.pdf appendix.pdf --out combined.pdf -pdfcraft-cli extract report.pdf --pages 1,3,5 --out highlights.pdf -pdfcraft-cli split report.pdf --every 10 --out-dir parts/ +```bash +git clone https://github.com/b-lincko/linkco-pdf.git +cd linkco-pdf +python build.py ``` --- -## Open protected documents and respect their rules - -PdfCraft implements the PDF standard security handler completely: -- every revision, from 40-bit RC4 to AES-256; -- user and owner passwords, including Unicode passwords normalised with SASLprep; -- crypt filters and attachment-only encryption. - -Documents restricted by their author show a clear notice, and PdfCraft honours their permissions. Enter the owner password and the restrictions lift. Edits to encrypted documents are saved encrypted, under the same keys. - - - - - - -
The Document Properties dialog on its Description tab, with editable title, author, subject and keywords, and tabs for Security, Fonts and Advanced
Document Properties, Description tab
- -**Document Properties** shows: -- the document's title, author, subject and keywords, which you can edit; -- the fonts it uses and whether each is embedded; -- PDF version, page size, tags, fields, layers and attachments; -- the full security picture: encryption method, which password opened it, and each permission. - -
- -## Comments, forms, layers and attachments - - - - - - - - - - -
The Interactive Form page with highlighted text fields, checkboxes, radio buttons, a list and a signature field, and the Fields panel listing all 13 fields and their valuesThe Review and Markup page with highlights, shapes, ink and an APPROVED stamp under a DRAFT watermark, and the Layers panel with Draft watermark and Print-only notes
Forms: every field with its current value, field highlighting, and checkboxes, radio buttons, lists and signatures drawn the way their author designed them.Layers: switch optional content on and off and the page re-renders instantly. Comments appear as threaded conversations, and attachments can be opened or saved.
- -## Every tool, one keystroke away - -Press ⌘K to search every tool and command, or browse the **All tools** catalogue. Tools that are still in development are marked with the milestone that will ship them. - - - - - - - - - - -
The command palette searching for 'page', listing Page grid, Page labels, Rotate pages, Insert pages, Delete pages, Extract pages and more, each with the tool it belongs toThe Welcome to PdfCraft home screen with recommended tools, a recent file, a privacy note, and the full tool catalogue in the side panel
The ⌘K command paletteThe home screen and the All tools catalogue
- ---- +## Windows Installer + +The Windows packaging pipeline lives in `packaging/windows/` and embeds full Linkco product metadata into both the executable (`apps/pdfcraft/build.rs`) and the installers: + +- **Product Name:** `Linkco PDF Editor` +- **Publisher / Company Name:** `Al Rawabet Commercial Services & Contracting Company W.L.L.` +- **Internal Name:** `LinkcoPDFEditor` +- **Original Filename:** `LinkcoPDFEditor.exe` +- **Application Icon:** `assets/app-icon/pdfcraft.ico` +- **Shortcuts Created:** + - Start Menu: `Linkco PDF Editor` + - Desktop: `Linkco PDF Editor` +- **Windows File Explorer Preview Pane (`IPreviewHandler`):** Installs and registers `LinkcoPdfPreviewHandler.dll` (`CLSID {D4E7B6A2-4C91-4E3A-9B12-7A8F5C3E1D20}`) for `.pdf` files, backing up any previously registered preview handler and restoring it cleanly on uninstall. +- **Network shares and downloaded files in the Preview Pane:** PDFs on `\\fileserver\share` shares, mapped drives, OneDrive and local disks preview normally. Since the October 2025 Windows update, File Explorer itself blocks the preview pane (before any preview handler runs) for files in the *Internet* zone: shares reached by a dotted name or IP address, and downloaded files with the Mark of the Web. To see why a file shows no preview, and to list a trusted server as a Local intranet site for your account only, run in PowerShell: + ```powershell + $dll = "$env:ProgramFiles\Linkco\Linkco PDF Editor\LinkcoPdfPreviewHandler.dll" # per-user install: $env:LOCALAPPDATA\Programs\Linkco\Linkco PDF Editor\… + $t = [Reflection.Assembly]::Load([IO.File]::ReadAllBytes($dll)).GetType('LinkcoPdfPreview.LinkcoPdfPreviewHandler') + $t::DiagnoseFile('\\files.corp.example.com\share\drawing.pdf') + $t::AllowNetworkPreview('files.corp.example.com') # undo: $t::DisallowNetworkPreview('files.corp.example.com') + ``` + For a downloaded file you trust, use `Unblock-File -LiteralPath ` (or *Properties ▸ Unblock*). +- **Image Context Menu Integration:** Adds `Create PDF with Linkco PDF Editor…` to `.png`, `.jpg`, `.jpeg`, `.tif`, `.tiff`, `.gif`, `.bmp`, `.jp2`, `.j2k`, and `.jpx` context menus without altering default image file associations. +- **Installed Apps Registration:** Registers **Linkco PDF Editor** in Windows *Installed Apps / Add or Remove Programs* with version, icon, publisher, and clean uninstaller support, and registers `.pdf` under *Open With* without overriding the user's default PDF handler. -## Runs everywhere, stays yours +### Building the Windows Installer -- **Native on macOS, Windows, Linux and FreeBSD**, and **in the browser** through WebAssembly, from the same Rust codebase. Windows builds come for x64, x86 and ARM64 (Windows on ARM, no emulation); every ARM64 change is tested on ARM64 hardware in CI. -- **Private by design.** Documents never leave your machine. There's no account, no telemetry and no cloud processing. -- **Engine first.** Parsing, rendering and editing live in reusable library crates. The interface is one swappable layer on top. -- **Scriptable.** The `pdfcraft-cli` tool (see [Built for agents, too](#built-for-agents-too)) covers inspecting, rendering, extracting text, editing, combining, extracting pages and splitting. Robustness sweeps run on the same engine as the app. +On Windows (with Python 3 and the Rust toolchain installed), run `installer.py`: -```sh -pdfcraft-cli info form.pdf # structure as JSON -pdfcraft-cli text paper.pdf --page 3 # reading-order text -pdfcraft-cli edit in.pdf --rotate 1,2:90 --delete 5 --title "Q3" --out out.pdf +```bash +python installer.py ``` ---- - -## Built for agents, too - -Every engine feature is reachable without the GUI, through one table of JSON-Schema-described tools: open, inspect, render pages to PNG, extract and find text, rotate, delete, move and insert pages, edit bookmarks and page labels, add, reply to, restyle and delete comments (highlight a phrase just by naming it), list and fill in form fields, protect with passwords, set metadata, undo and redo, save, combine, extract and split. Three front doors share it: +Or from PowerShell using WiX Toolset v5 (`wix`) and optionally NSIS (`makensis`): -- **`pdfcraft-cli run`**, for one-off calls and JSON scripts: - - ```sh - pdfcraft-cli tools # every tool and its JSON Schema - pdfcraft-cli run text_find doc=1 query=invoice # key=value; values parse as JSON - pdfcraft-cli run --script review.json # e.g. comment_add {"type": "highlight", "find": "total due"} - pdfcraft-cli run --script steps.json --root ./work # several steps in one session - ``` - - With `--root`, every file the script's steps read or write stays in that directory, including the PNG a step saves with `"out"` (the script itself is read from wherever you name it). - -- **An MCP server**, for AI agents such as Claude. **It is opt-in:** PdfCraft never starts it on its own, and it opens no network port. It runs only while an agent launches `pdfcraft-cli mcp`, talks over stdin/stdout, and stops when the agent disconnects. To enable it, add it to your agent's MCP configuration: - - ```json - { "mcpServers": { "pdfcraft": { "command": "pdfcraft-cli", "args": ["mcp", "--root", "/path/to/your/pdfs"] } } } - ``` +```powershell +pwsh -File packaging/windows/package.ps1 +``` - `--compact` shrinks the tool list the agent has to read: `tools/list` returns about ten core tools plus `tool_search` and `tool_call`, which find and run every other tool, so the list costs far fewer tokens. Every tool still works. +This builds the Windows release binaries, fetches the OCR models (`cargo xtask models`), and produces in `dist/release/`: +- `dist/release/LinkcoPDFEditorSetup.exe` (standalone Windows GUI installer — built via NSIS `makensis` when installed, or automatically via Windows' built-in `.NET` `csc.exe` compiler, supporting both Administrator per-machine and standard per-user installations) +- `dist/release/LinkcoPDFEditorSetup--windows-.msi` (when WiX v5 is installed; validated by `packaging/windows/test-msi.ps1`) +- `dist/release/LinkcoPDFEditor--windows--portable.zip` (portable ZIP containing `pdfcraft.exe`, `pdfcraft-cli.exe`, `models\`, and `portable.txt`) - `--root` confines every file the agent can read or write to one directory. Builds that should not include the server at all can use `cargo build -p pdfcraft-cli --no-default-features`. +--- -- **The Rust API** (`pdfcraft_automation::Automation::call`), for embedding. +## Usage -Edits stay in memory, undoable, until `doc_save`. Saving to the same file appends an incremental update, so the original bytes are preserved, and the write is atomic. Unsaved changes are never discarded silently. +### Desktop GUI -### Driving the app itself +Launch the desktop editor directly or pass one or more PDF files on the command line: -Start the desktop app with `pdfcraft --control ~/.pdfcraft-control.json` and an agent can see and operate the real interface: the widget tree with labels and positions (from the accessibility tree), clicks, typing, keys, commands, view options and screenshots. This is also off by default. It listens only on loopback, and every connection must present the random token written to that file, which only you can read. +```bash +# Open the Home dashboard +cargo run --release -p pdfcraft -Keep the control file in a folder only you can write, not a shared one such as `/tmp`: another user could create the file there first and receive your commands. `pdfcraft-cli ui` refuses a control file that is a symbolic link, and on macOS, Linux and FreeBSD one that another user owns or can read or write. The app doesn't start if it can't write the file. +# Open specific PDF files at a target page +cargo run --release -p pdfcraft -- --page 1 document.pdf -```sh -pdfcraft-cli ui --control ~/.pdfcraft-control.json inspect query=rotate # find widgets -pdfcraft-cli ui --control ~/.pdfcraft-control.json click label="Organize pages" -pdfcraft-cli ui --control ~/.pdfcraft-control.json key key=K modifiers='["command"]' -pdfcraft-cli ui --control ~/.pdfcraft-control.json command id=comment.square # pick a tool, then draw: -pdfcraft-cli ui --control ~/.pdfcraft-control.json drag from='[400,300]' to='[600,420]' -pdfcraft-cli ui --control ~/.pdfcraft-control.json screenshot --out window.png -pdfcraft-cli ui --control ~/.pdfcraft-control.json resize width=1200 height=800 -pdfcraft-cli ui --control ~/.pdfcraft-control.json focus label="Read" -pdfcraft-cli ui --control ~/.pdfcraft-control.json inspect focused=true -pdfcraft-cli ui --control ~/.pdfcraft-control.json quit +# Force the OpenGL (glow) renderer instead of wgpu +cargo run --release -p pdfcraft -- --renderer glow ``` -`ui.dock` arranges the `tools` and `inspector` panels; `canvas` is the protected document view. -Each per-panel request requires a `panel` ID and an `operation`: `open`, `close`, -`activate`, `float` with `rect: [x, y, width, height]`, or `move` with `target` and -`zone: center|left|right|top|bottom`. For example, -`{"operation":"float","panel":"tools","rect":[100,100,320,440]}` floats Tools. -`ui.dock.reset` restores the default -arrangement. The control channel accepts these methods directly; `ui.command` also accepts -`{"id":"ui.dock","params":{...}}`. Saved preferences retain groups, active tabs, visibility -and floating geometry. Invalid requests return an error without changing the document or layout. +### Command-Line Interface (`pdfcraft-cli`) +The companion CLI binary supports headless inspection, text extraction, page rendering, encryption, optimization, batch processing, and MCP server execution: -`resize` requests a native inner-window size in logical points (each dimension must be between 320 and 8192); the window manager may constrain it. `state` reports the observed `window.width`, `window.height` and `window.pixels_per_point`. `focus` accepts exactly one widget `id` or unique enabled, focusable `label`; subsequent `key` requests traverse or activate the actual widgets. `inspect` includes focusability and accepts a `focused` filter. `quit` takes no parameters: clean documents exit normally, while unsaved edits or typing open the existing Save/Don't save/Cancel prompt and return `quitting: false, needs_confirmation: true`. It never silently discards work. Window resizing and application quit are native-only. +```bash +# Inspect document metadata, page count, and PDF version +cargo run --release -p pdfcraft-cli -- info document.pdf ---- +# Render pages to PNG images at 150 DPI +cargo run --release -p pdfcraft-cli -- render document.pdf --dpi 150 --out page-1.png -## How it's built - -PdfCraft is a Cargo workspace of focused crates, layered so the core never depends on the UI: - -| Crate | What it does | -|---|---| -| `pdfcraft-filters` | Every PDF stream filter (Flate, LZW, ASCII85, RunLength, predictors), encode and decode, property-tested | -| `pdfcraft-crypt` | The standard security handler: RC4, AES-128/256, revisions 2–6, permissions | -| `pdfcraft-cos` | The PDF object layer: tolerant parsing, repair, copy-on-write edits, incremental and full writing | -| `pdfcraft-organize` | Page operations, combine / extract / split, bookmarks, page labels, document information | -| `pdfcraft-fonts` | Font metrics and encodings for generated appearances | -| `pdfcraft-annot` | Comments: builders and appearance streams for notes, text markup, shapes, ink and text boxes; replies, status, edits | -| `pdfcraft-forms` | Interactive forms: the field model, filling with regenerated appearances, Clear form | -| `pdfcraft-render` | Rendering, inspection and text extraction with reading order | -| `pdfcraft-engine` | The façade every frontend uses: sessions, edits, undo, saving, the tool catalogue | -| `pdfcraft-automation` | Agent control: the headless tool table, `pdfcraft-cli run`, and the opt-in MCP server | -| `pdfcraft-ui-egui` | The desktop and web interface | - -**Quality gates.** Every change passes the same automated checks: -- formatting, and Clippy with warnings as errors; -- 200+ unit, property and UI tests; -- crate-layering rules and a WebAssembly build check; -- an asset-licence audit. - -On top of those, two corpus sweeps run over real-world files: -- **Opening and rendering:** of the 983 pdf.js test files, 963 open and render cleanly, with 0 crashes. -- **Open, edit and save round trips:** 958 succeed. - -The output is verified with independent tools: hayro, qpdf and poppler. - -PdfCraft is a clean-room implementation. Its behaviour comes from the ISO 32000 specification and black-box observation, never from anyone else's code. Every icon, font and image is openly licensed and listed in [ATTRIBUTION.md](ATTRIBUTION.md). - -## Get started - -```sh -git clone https://github.com/storytold/pdfcraft -cd pdfcraft -cargo run --release -p pdfcraft -- some.pdf # desktop app -cargo xtask demo-pdf # build the showcase PDF used in these screenshots -cargo xtask screenshots # regenerate every screenshot in this README -``` - -The interface language is chosen in **Menu → Edit → Preferences…** (Command-comma on macOS, -Ctrl-comma elsewhere, also with no document open; Auto follows the system language; -see [docs/localization.md](docs/localization.md)) and saved. Japanese covers commands, -dialogs, panels and keyboard shortcuts. Command search accepts the translated label, the -English label and the stable command id; filenames, PDF contents, author names, custom -action names and error details from the engine or the operating system keep their own text. +# Generate a single-page preview image with structured status output (used by the Windows Preview Handler) +cargo run --release -p pdfcraft-cli -- preview document.pdf --page 1 --dpi 150 --out preview.png +# …or fit a given pixel width (what the Explorer preview pane asks for), capping the longer side +cargo run --release -p pdfcraft-cli -- preview document.pdf --page 1 --width 800 --max-px 4096 --out preview.png -Japanese fonts come from [craft-fonts](https://github.com/storytold/craft-fonts), an optional build -input that every release includes. To build with them (Japanese interface text, and Japanese text in -edited PDFs): +# Extract plain text from a PDF +cargo run --release -p pdfcraft-cli -- text document.pdf -```sh -git clone https://github.com/storytold/craft-fonts ../craft-fonts -CRAFT_FONTS_DIR=../craft-fonts cargo run --release -p pdfcraft -- some.pdf +# Start the opt-in Model Context Protocol (MCP) server over stdio +cargo run --release -p pdfcraft-cli -- mcp --compact ``` -Each [GitHub release](https://github.com/storytold/pdfcraft/releases) has ready-made builds for macOS, -Windows, Linux (AppImage, Flatpak, `.deb`, `.rpm` and a tarball), FreeBSD and the web; see -[Downloads](#downloads). On Gentoo, the community [::snakebyte -overlay](https://github.com/switch87/snakebyte-overlay) packages the Linux release as -`app-text/pdfcraft-bin` (not maintained by the PdfCraft team): - -```sh -eselect repository add snakebyte git https://github.com/switch87/snakebyte-overlay.git -emaint sync -r snakebyte -echo 'app-text/pdfcraft-bin ~amd64' >> /etc/portage/package.accept_keywords/pdfcraft -emerge --ask app-text/pdfcraft-bin -``` - -Logs, environment variables and other development notes are in [docs/development.md](docs/development.md). - -## What's next +### Driving the Running App (agents and UI automation) -PdfCraft is young and moving fast. The aim is a workbench where you can view, organize, annotate, fill, sign and edit PDFs, at parity with Acrobat Pro. +Start the editor with a control file and an agent (or a test script) can see and operate the real interface: the widget tree with labels and positions, clicks, typing, keys, commands, panel layout and screenshots. The control channel is off unless `--control` is given; it then listens only on a random loopback port (this computer only) and requires the token written to the owner-only control file. Keep the control file in a folder only you can write; `pdfcraft-cli ui` refuses a control file that is a symbolic link. -**Where it stands (October 2026), honestly:** PdfCraft is **alpha**. Most of Acrobat Pro's offline features exist in some form (57% of all tracked features, 94% of the must-haves). For everyday work (viewing, commenting, filling and signing forms, organizing pages) it is about 55% of the way to replacing Acrobat; against all of Acrobat Pro, about 49%; for someone who only needs the essentials, about 66%. Every everyday workflow can be completed, but converting and sharing is weak: password-protected files Acrobat can't open, no Office-to-PDF, and Word export that loses layout. - -- **Good today:** viewing and search; organizing, combining and splitting; most kinds of comment; filling and authoring forms (with sandboxed JavaScript); passwords, redaction and sanitizing; basic digital signatures; printing; the Accessibility Checker; agent control through the CLI and MCP. -- **Still borrowed:** pages are drawn by the `hayro` crate while our own renderer is built. -- **Thin or missing:** reliable editing of existing text (especially CJK and right-to-left), OCR beyond Latin script, Office import/export, signature tokens and online long-term validation, Preflight and PDF/X/UA, printing on Windows, and full XFA forms. -- **Hardening:** fuzzing still turns up crashes and hangs on hostile files; each one is fixed with a regression test. Quality has not yet been compared with Acrobat side by side. - -**Next, in order:** encrypted files that Acrobat opens, the reported bugs and Windows printing, a fidelity harness against Acrobat and the renderer, editing existing content, then the Pro workflows (OCR, Office, Preflight, signatures, accessibility tagging) and 1.0 polish. +```bash +pdfcraft --control ~/.linkco-control.json # LinkcoPDFEditor.exe on Windows +pdfcraft-cli ui --control ~/.linkco-control.json inspect query=rotate # find widgets +pdfcraft-cli ui --control ~/.linkco-control.json click label="Organize pages" +pdfcraft-cli ui --control ~/.linkco-control.json resize width=1200 height=800 +pdfcraft-cli ui --control ~/.linkco-control.json focus label="Read" +pdfcraft-cli ui --control ~/.linkco-control.json inspect focused=true +pdfcraft-cli ui --control ~/.linkco-control.json screenshot --out window.png +pdfcraft-cli ui --control ~/.linkco-control.json quit # with unsaved changes, shows the save prompt instead of quitting +``` -The summary is in **[ROADMAP.md](ROADMAP.md)**; the full assessment by dimension and area is in [docs/target-app-parity.md](docs/target-app-parity.md), the ranked gaps in [docs/gaps.md](docs/gaps.md), and the milestones in [docs/roadmap.md](docs/roadmap.md). +`resize` requests a native window size in logical points (320–8192 per dimension). `focus` takes one widget `id` or a unique, enabled `label`; later `key` requests move through or activate the real widgets. `ui.dock` arranges the `tools` and `inspector` panels (`canvas` is the protected document view): each request names a `panel` and an `operation` — `open`, `close`, `activate`, `float` with `rect: [x, y, width, height]`, or `move` with `target` and `zone: center|left|right|top|bottom` — for example `{"operation":"float","panel":"tools","rect":[100,100,320,440]}`. `ui.dock.reset` restores the default layout. Invalid requests return an error without changing the document or the layout. --- -## Downloads +## Development -**New to PdfCraft?** Download it from the [PdfCraft page on getartcraft.com](https://getartcraft.com/apps/pdfcraft). That's the easiest way to install it. +### Prerequisites -**Want a specific build or format?** On GitHub, the [latest release](https://github.com/storytold/pdfcraft/releases/latest) has every build listed below, and [all releases](https://github.com/storytold/pdfcraft/releases) has earlier versions and their notes. `` in the file names is the version number, and `SHA256SUMS.txt` lists a checksum for every file. +- Rust toolchain (`rustc` and `cargo` supporting Rust 2024 edition) +- On Linux, standard GUI development headers (`libxcb`, `libxkbcommon`, `libwayland`, `libfontconfig`, `libasound2`) -### Windows +### Useful Workspace Commands -| Build | Installer | Portable | -|---|---|---| -| x64 (64-bit Intel/AMD) | `pdfcraft--windows-x64.msi` | `pdfcraft--windows-x64-portable.zip` | -| arm64 (Snapdragon and other ARM PCs) | `pdfcraft--windows-arm64.msi` | `pdfcraft--windows-arm64-portable.zip` | -| x86 (32-bit) | `pdfcraft--windows-x86.msi` | `pdfcraft--windows-x86-portable.zip` | +```bash +# Verify asset attribution and regenerate ATTRIBUTION.md +cargo xtask assets -Installers and executables are code-signed. +# Fetch OCR models into assets/models/ +cargo xtask models -The portable zip runs from any folder, a USB stick included. Its `portable.txt` keeps the settings, -logs and crash recovery in a `PdfCraftData` folder next to `pdfcraft.exe`, so nothing is written to -`%APPDATA%`; delete that file to use the normal per-user folders. +# Run repository engineering gates (no unsafe, no panics, licence & metadata checks) +cargo xtask gates -The MSI installs for all users and requires administrator privileges. For unattended deployment -without a desktop shortcut, run from an elevated terminal: +# Verify workspace version consistency across packaging manifests +cargo xtask version -```powershell -msiexec /i "pdfcraft--windows-x64.msi" /qn /norestart INSTALLDESKTOPSHORTCUT=0 +# Verify feature parity matrix against engine commands +cargo xtask parity ``` -Use the MSI for your architecture. Per-user installation overrides are not supported. - -### macOS - -| Build | File | Notes | -|---|---|---| -| App, universal (Apple silicon + Intel) | `pdfcraft--macos-universal.dmg` | Signed and notarized | -| Command-line tool, universal | `pdfcraft-cli--macos-universal.zip` | Signed and notarized | - -### Linux - -| Format | x86_64 | aarch64 (ARM64) | Notes | -|---|---|---|---| -| AppImage | `pdfcraft--linux-x86_64.AppImage` | `pdfcraft--linux-aarch64.AppImage` | Runs anywhere; updates itself with [AppImageUpdate](https://github.com/AppImageCommunity/AppImageUpdate) (`.zsync` files) | -| Flatpak | `pdfcraft--linux-x86_64.flatpak` | `pdfcraft--linux-aarch64.flatpak` | Sandboxed; `flatpak install --user ` | -| Debian/Ubuntu | `pdfcraft--linux-x86_64.deb` | `pdfcraft--linux-aarch64.deb` | | -| Fedora/RHEL/openSUSE | `pdfcraft--linux-x86_64.rpm` | `pdfcraft--linux-aarch64.rpm` | | -| Tarball | `pdfcraft--linux-x86_64.tar.gz` | `pdfcraft--linux-aarch64.tar.gz` | Unpack anywhere | -| Command-line tool | `pdfcraft-cli--linux-x86_64.tar.gz` | `pdfcraft-cli--linux-aarch64.tar.gz` | `pdfcraft-cli` alone (and its opt-in MCP server), for servers, CI and agents | +--- -RISC-V (riscv64) builds come as tarballs only: `pdfcraft--linux-riscv64.tar.gz` and `pdfcraft-cli--linux-riscv64.tar.gz`. They are cross-compiled and need glibc 2.39 or newer (Ubuntu 24.04+, Debian 13+). +## Build -Every other Linux build needs glibc 2.35 or newer (Ubuntu 22.04+, Debian 12+, Fedora 36+, RHEL 10). +```bash +# Build release binaries into dist/release/ using the Python build script +python build.py -### FreeBSD +# Build the Windows application + Windows Setup installer (LinkcoPDFEditorSetup.exe) +python installer.py -| Build | File | -|---|---| -| x86_64 | `pdfcraft--freebsd-x86_64.tar.gz` | +# Or build directly with Cargo +cargo build --release -p pdfcraft -p pdfcraft-cli +``` -### Web (WebAssembly) +`build.py` and `installer.py` fetch the [craft-fonts](https://github.com/storytold/craft-fonts) build input (Japanese fonts and Noto Sans Arabic, about 70 MB, into the git-ignored `craft-fonts/` folder) at the commit pinned in `.github/workflows/release.yml`, and copy the fonts' `OFL-*.txt` licences next to the binaries. These fonts are what let the editor **write Arabic and Japanese text into PDFs**; the Arabic interface itself also works with Windows' own Segoe UI. Pass `--no-craft-fonts` (or set `LINKCO_NO_CRAFT_FONTS=1`) to skip the download, or `CRAFT_FONTS_DIR=` to use an existing checkout. A plain `cargo build` builds without them unless `CRAFT_FONTS_DIR` is set. -| Build | File | Notes | -|---|---|---| -| Static site | `pdfcraft-web-.zip` | Runs in a modern browser; host it on any static server | +Compiled binaries are placed in `dist/release/LinkcoPDFEditor.exe` (`dist/release/LinkcoPDFEditor` on Linux/macOS) as well as `target/release/pdfcraft` and `target/release/pdfcraft-cli`. --- -## The Crafting Apps +## Testing -PdfCraft is one of the **Crafting Apps**: free, open-source creative tools from the -[ArtCraft](https://getartcraft.com/) team, each written from scratch in Rust and each able to -stand on its own. +Run the workspace unit and integration test suites: -| | App | What it's for | Code | Learn more | -|:-:|---|---|---|---| -| | **PhotoCraft** | Image editing: layers, masks, type and real PSD files | [GitHub](https://github.com/storytold/photocraft) | [Website](https://getartcraft.com/apps/photocraft) | -| | **VectorCraft** | Vector illustration | [GitHub](https://github.com/storytold/vectorcraft) | [Website](https://getartcraft.com/apps/vectorcraft) | -| | **FilmCraft** | Video editing, color and sound | [GitHub](https://github.com/storytold/filmcraft) | [Website](https://getartcraft.com/apps/filmcraft) | -| | **LightCraft** | Photo library and raw development | [GitHub](https://github.com/storytold/lightcraft) | [Website](https://getartcraft.com/apps/lightcraft) | -| | **PdfCraft** | **Reading, organizing and protecting PDFs · you are here** | [GitHub](https://github.com/storytold/pdfcraft) | [Website](https://getartcraft.com/apps/pdfcraft) | -| | **EffectCraft** | Motion graphics and visual effects | [GitHub](https://github.com/storytold/effectcraft) | [Website](https://getartcraft.com/apps/effectcraft) | -| | **DesignCraft** | Page layout and publishing | [GitHub](https://github.com/storytold/designcraft) | [Website](https://getartcraft.com/apps/designcraft) | +```bash +# Run all workspace library and integration tests +cargo test --workspace -And [**ArtCraft**](https://getartcraft.com/) itself, our AI image and video studio for artists who want real control. +# Run UI integration tests (home dashboard, links, pickers, signing, keyboard shortcuts) +cargo test -p pdfcraft-ui-egui -
+# Run engine unit tests (catalog, commands, links, redaction, editing) +cargo test -p pdfcraft-engine -

- Join the ArtCraft community on Discord -

- -

Come make things with us

+# Run clippy lints across all targets +cargo clippy --workspace --all-targets -- -D warnings +``` -

- Our Discord is where artists of every kind hang out: people who paint, shoot, draw, cut film, - set type, and people still figuring out what they like to make. Share what you're working on, - ask for help, tell us what's broken, or tell us what you wish these tools could do. - Whatever your medium and however long you've been at it, you're welcome here. -

+--- -

- discord.gg/artcraft · - getartcraft.com · - The Crafting Apps · - PdfCraft -

+## Project Structure + +```text +linkco-pdf/ +├── apps/ +│ ├── pdfcraft/ # Desktop GUI binary (Linkco PDF Editor) & Windows resource script +│ ├── pdfcraft-cli/ # Headless CLI, single-page preview renderer, batch runner, and MCP host +│ └── pdfcraft-web/ # WebAssembly browser application target +├── crates/ +│ ├── cos/ # PDF 1.7 / 2.0 object model, zero-copy file-backed streams, and incremental writer +│ ├── filters/ # Stream compression and decompression filters (Flate, LZW, RunLength, ASCII85/Hex) +│ ├── crypt/ # PDF standard security handler (RC4, AES-128, AES-256) and permission flags +│ ├── geom/ # 2D geometry primitives (points, rectangles, affine matrices) +│ ├── model/ # High-level document tree (pages, outlines/bookmarks, page labels, layers, attachments) +│ ├── fonts/ # Standard 14 PDF font metrics, Arabic/BiDi shaping, and embedded CJK/Indic/Cyrillic fonts +│ ├── content/ # PDF content stream tokenizer, text extraction, and full-text search +│ ├── render/ # PDF page renderer (backed by hayro) and document inspector +│ ├── organize/ # Page rotation, deletion, insertion, extraction, splitting, combining, and page boxes +│ ├── annot/ # PDF annotations, appearance stream generation, and link editing +│ ├── xfdf/ # ISO 19444-1 XFDF and FDF comment/form data import and export +│ ├── forms/ # AcroForm field reading, filling, authoring, and rotated appearance streams +│ ├── js/ # Sandboxed Acrobat form JavaScript runtime (backed by boa_engine) +│ ├── xfa/ # XFA template layout, FormCalc/JavaScript execution, and datasets sync +│ ├── edit/ # Multi-stream text reflow/editing, Form XObject figures, images, headers/footers, watermarks +│ ├── create/ # PDF creation from multiple files, images, plain text, HTML, and blank templates +│ ├── export/ # PDF export to Word (.docx), HTML, Rich Text (.rtf), PNG images, and plain text +│ ├── sign/ # PKCS#7 / CMS and PAdES digital signatures, Windows CNG store, and X.509 certificates +│ ├── redact/ # True content-stream text/image redaction and hidden-information sanitization +│ ├── optimize/ # File size reduction, image resampling, stream compression, and space audit +│ ├── ocr/ # Optical character recognition pipeline and searchable PDF text layer generation +│ ├── compare/ # Word-by-word and visual document comparison +│ ├── measure/ # Distance, perimeter, and area measurement tools with vector snapping and CSV export +│ ├── print/ # Sheet imposition (Size, Multiple, Cut & Stack, Booklet, Poster) and OS print spooler +│ ├── preflight/ # PDF/A-2b and PDF/A-3b verification and conversion +│ ├── a11y/ # 32-rule PDF accessibility checker, fixes, alternate text, and HTML reporting +│ ├── engine/ # Unified document session facade, command registry, tool catalog, and Action Wizard +│ ├── automation/ # Headless automation tool table and opt-in Model Context Protocol (MCP) server +│ └── ui-egui/ # Immediate-mode desktop/web UI shell, Home dashboard, dialogs, and 16 i18n catalogs +├── assets/ +│ ├── app-icon/ # Linkco PDF Editor application icons (.svg, .ico, .icns, .png) +│ ├── fonts/ # Bundled UI and PDF fonts +│ └── icons/ # Bundled Lucide UI icons (ISC licence) +├── docs/ +│ └── images/ # Local application screenshots used in documentation +├── packaging/ +│ ├── windows/ # Windows WiX (.wxs), NSIS (installer.nsi), PreviewHandler.cs, and PowerShell scripts +│ ├── macos/ # macOS .app / .dmg / .pkg packaging scripts +│ ├── linux/ # Linux .deb, .rpm, AppImage, Flatpak, and tarball scripts +│ └── freebsd/ # FreeBSD packaging scripts +├── build.py # Cross-platform Python build script for Linkco PDF Editor binaries +├── installer.py # Windows installer build script (produces LinkcoPDFEditorSetup.exe) +└── xtask/ # Workspace engineering gates, asset attribution, version, and parity tasks +``` --- -## License and credits +## Security & Privacy -PdfCraft is dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option. -Copyright (c) 2026 ArtCraft Team and the PdfCraft contributors. Required notices are in [NOTICE](NOTICE). +- **Local Document Processing & Network Policy:** Linkco PDF Editor processes all PDF files locally on your workstation and includes no analytics, telemetry, crash-reporting beacons, or advertisements. The application performs no background network requests; the only network activity is the optional, user-initiated `Help ▸ Check for updates…` action (`apps/pdfcraft/src/updates.rs`), which queries the GitHub Releases API (`https://api.github.com/repos/b-lincko/linkco-pdf/releases/latest`) when clicked and never downloads or installs updates automatically. +- **Memory-Safe Architecture:** `unsafe_code = "forbid"` is enforced across all workspace crates (`crates/`, `apps/`, `xtask/`), preventing buffer overflows and memory corruption in workspace code when parsing untrusted PDF files. +- **External Link Protection:** Clicking a link inside a PDF document never opens a browser or executes a local file path silently; only `https://`, `http://`, and `mailto:` schemes are permitted, and every external URL requires explicit user confirmation in a modal dialog showing the full destination address (with homograph/mixed-script warnings). +- **Sandboxed Scripting:** Document JavaScript (`crates/js`) and XFA scripts (`crates/xfa`) execute inside an isolated `boa_engine` sandbox with strict loop-iteration, recursion, and execution-time limits and zero filesystem or network access. +- **Corporate Certifications Note:** References to ISO 9001, ISO 14001, and ISO 45001 refer to the corporate quality, environmental, and occupational health & safety management certifications of **Al Rawabet Commercial Services and Contracting Company W.L.L. (Linkco)**, not third-party cryptographic or software security certifications of the binary. -Bundled fonts, icons, images and other assets keep their own open licenses; each one is listed -with its author, source and license in [ATTRIBUTION.md](ATTRIBUTION.md). Release builds also embed -the Japanese fonts of [craft-fonts](https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md) -(SIL Open Font License 1.1). +--- -The ArtCraft name, wordmark and logos in [`docs/brand/`](docs/brand/) are trademarks of the -ArtCraft Team and are not covered by this license. They may be used only unmodified, and only as -part of this repository and PdfCraft, under [`docs/brand/LICENSE-brand.txt`](docs/brand/LICENSE-brand.txt). -Forks and modified versions must remove them. +## License -Adobe, Photoshop, Illustrator, Premiere Pro, Lightroom, Acrobat, After Effects and InDesign are trademarks or registered trademarks of Adobe Inc. in the United States and/or other countries. PdfCraft is an independent, open-source project and is not affiliated with, sponsored by or endorsed by Adobe Inc.; these names are used only to describe the workflows it is compatible with. +Dual-licensed under either of: -

- ArtCraft
- Made by the ArtCraft team and community. -

+- **Apache License, Version 2.0** ([`LICENSE-APACHE`](LICENSE-APACHE)) +- **MIT License** ([`LICENSE-MIT`](LICENSE-MIT)) -Tools and Inspector panels can be dragged into tab groups, split beside the PDF, or floated within the app window. Read and full-screen modes keep their existing focused document view. Drag a panel header to a target edge or another header. Its context menu offers Float panel, Move to group, and Close panel. Existing panel toggles reopen panels at their saved location; Reset Panel Layout restores the app layout. Floating panels remain inside the current app window. +at your option. Third-party font and icon attributions are cataloged in [`ATTRIBUTION.md`](ATTRIBUTION.md). -Advanced `ui.dock` operations use the same validated transaction as pointer gestures: -`moveFloating` updates `rect`, `resizeSplit` accepts a boolean child `path` and -`size` (`{"Ratio":0.5}`, `{"FixedFirst":280}`, or `{"FixedSecond":280}`), -`setStackOpen` takes `open`, and `resizeStack` takes a point `height` or null. -A center `move` can include `before` (panel ID or null to append) for tab order. -The equivalent `{"action": ...}` form accepts a serialized shared docking action; -this is also the form emitted by the renderer. Protected-canvas and app-specific panel -rules apply equally to both forms. +Copyright © Al Rawabet Commercial Services & Contracting Company W.L.L. (Linkco) +Developed by **Muhammad Bilal** (Linkco) +Building 159, Street 220, Zone 24, P.O. Box 32282, Doha – Qatar · Phone: +974 4437 2511 · Email: `info@linkco.com.qa` · Web: `www.linkco.com.qa` diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md new file mode 100644 index 0000000000..8a7d5c2424 --- /dev/null +++ b/RELEASE_NOTES.md @@ -0,0 +1,224 @@ +# Linkco PDF Editor v1.0.0 — Release Notes + +**Product:** Linkco PDF Editor +**Version:** `1.0.0` +**Publisher:** Al Rawabet Commercial Services & Contracting Company W.L.L. (Linkco) +**Developer:** Muhammad Bilal (Linkco) +**Location:** Building 159, Street 220, Zone 24, P.O. Box 32282, Doha – State of Qatar (`www.linkco.com.qa`) + +--- + +## What's new in v1.0.0 + +v1.0.0 is the first final release of Linkco PDF Editor. It contains everything from v0.6.0 below, plus the following changes. + +### 1. Network printers on the Print screen +- **Network printers are recognised however they are connected:** + - shared printers (`\\server\printer`); + - Standard TCP/IP ports, whether named `IP_10.0.0.5` or (as current Windows names them) after the address or host, e.g. `10.0.0.5`, `10.0.0.5_1`, `printer.corp.local:9100`; + - WSD, IPP/`http(s)://` and LPR ports; + - any printer Windows itself reports as a network printer (`Win32_Printer.Network`). + + Before, only `IP_…` and `WSD…` ports and `\\server` names were recognised. +- **Printer list:** network printers are marked "· Network". A printer that can't print now shows its status in the interface language (Paused, Offline, Error). +- **Selected printer:** a line under the list shows "Network printer · Port: … · Driver: …", with the full text on hover. +- **Printer status warning:** this warning is now translated. +- **No printers found:** the dialog says so and suggests what to do: turn the printer on, connect it, then *Check again*, or save as PDF. + +### 2. File Explorer preview for PDFs on network shares, mapped drives and OneDrive +- **Where previews already work:** the preview pane and thumbnails work for PDFs on network shares reached by server name (`\\fileserver\share`), on mapped drives that point at them, in OneDrive/cloud folders (Windows downloads online-only files for the preview) and on local disks. +- **Where Windows blocks them:** since the October 2025 Windows update (KB5066835), File Explorer blocks the preview pane for files in the *Internet* or *Restricted sites* security zone. Explorer does this before it loads any preview handler. Two kinds of file are affected: + - files on shares reached by a dotted name (`\\files.corp.example.com\share`) or an IP address (`\\10.0.0.5\share`); + - downloaded files that carry the Mark of the Web. + + This is a Windows security decision. Linkco PDF Editor does not switch it off for every file. Instead it helps you check and fix it per file or per server (PowerShell, no administrator rights): + ```powershell + $dll = "$env:ProgramFiles\Linkco\Linkco PDF Editor\LinkcoPdfPreviewHandler.dll" # per-user install: $env:LOCALAPPDATA\Programs\Linkco\Linkco PDF Editor\… + $t = [Reflection.Assembly]::Load([IO.File]::ReadAllBytes($dll)).GetType('LinkcoPdfPreview.LinkcoPdfPreviewHandler') + $t::DiagnoseFile('\\files.corp.example.com\share\drawing.pdf') # location, security zone, Mark of the Web, and the fix + $t::AllowNetworkPreview('files.corp.example.com') # list a server you trust as a Local intranet site (current user) + $t::DisallowNetworkPreview('files.corp.example.com') # undo + Unblock-File -LiteralPath 'C:\Users\me\Downloads\drawing.pdf' # a downloaded file you trust + ``` +- **`AllowNetworkPreview`** writes the same per-user entry as *Internet Options ▸ Security ▸ Local intranet ▸ Sites ▸ Advanced*, under `HKCU\…\Internet Settings\ZoneMap`. It accepts a server name, a `\\server\share` path or a mapped-drive path. Where the organisation sets the zones by policy, it changes nothing and tells you to ask IT. +- **Thumbnail temp files:** temporary thumbnail images left behind when Windows stops a slow thumbnail are now cleaned up like the preview's own. + +### 3. File Explorer preview no longer keeps loading +- **Engine start:** the preview pane and thumbnails start the page engine (`pdfcraft-cli.exe`) directly, hidden, at below-normal priority. They no longer use .NET's process class. As a result: + - Windows no longer shows the spinning "app starting" cursor each time you select a PDF; + - waiting for the engine can't hang. Its output now goes to small temp files instead of pipes. Before, a pipe kept open by another process could leave the pane on "Loading…" forever; + - the engine runs in a job object that ends it if the Windows preview host closes, so no orphaned `pdfcraft-cli.exe` processes are left behind. +- **A page can no longer stay on "Loading…":** + - after 8 seconds the pane says the page is still loading; + - a watchdog ends any render that hasn't finished 10 seconds after the engine's 30-second time limit; + - a page that timed out or failed shows *Click to try again*. + + Finished pages also reach the pane even if a window message is lost. +- **Diagnostics:** `preview.log` (in `%USERPROFILE%\AppData\LocalLow\LinkcoPdfPreview`) now records each step with timings: stream copy, pane size, each render's result. `Diagnose()` (and `test-windows-integration.ps1`) now also: + - starts the engine as the preview does, and reports whether it ran and how long it took; + - says whether the preview host runs at low or normal integrity; + - shows the last 15 log lines; + - says which registration Windows actually uses (per-user or machine-wide), and whether its DLL exists or is blocked; + - creates the handler through COM as Explorer does, and reports the exact error if that fails; + - lists recent preview-host crashes from the Windows Application log. +- **New script, `packaging\windows\diagnose-preview.ps1`:** finds the registered DLL itself and prints all of the above. Add `-Pdf ` to check one file as well. +- **Fixed: "This file can't be previewed because of an error in the Linkco PDF Preview Handler" on every installed copy.** + - **Cause:** the handler's COM registration gave its location (`CodeBase`) as a percent-escaped URL, `file:///C:/Program%20Files/Linkco/Linkco%20PDF%20Editor/LinkcoPdfPreviewHandler.dll`. When .NET loads a COM server it does not decode `%20`, so the Windows preview host looked for a folder literally named `Program%20Files`, failed with `0x80070002` ("file not found") and Explorer showed that error. Every install under *Program Files* (whose name contains a space) was affected, whichever installer was used, because the app re-registers the handler for the current user when it starts, and that registration takes precedence. + - **Fix:** the app, the DLL and the Setup EXE now write `file:///C:/Program Files/…`, the form Microsoft's `regasm` writes. The NSIS and MSI installers already wrote a form .NET accepts. + - **Existing installs:** the registration schema went from 5 to 6, and the app now also rejects an escaped `CodeBase`, so the registration is repaired the next time Linkco PDF Editor starts. `diagnose-preview.ps1 -Repair` repairs it straight away. + - **Diagnostics now catch it:** `Diagnose()` and `diagnose-preview.ps1` resolve `CodeBase` the way .NET does and flag an escaped one. The COM activation test now creates the handler in a new native process, as `prevhost.exe` does. Before, it ran inside the calling PowerShell, which already had the DLL loaded, and passed even when Explorer could not load the handler. + - **Verified on Windows 11 24H2** (GitHub Actions, workflow *Windows preview handler*): a standard user registers per user, as the app does, and the handler is hosted in `prevhost.exe` the way Explorer hosts it. Every call succeeds and the pane paints. With the old `CodeBase`, the same test fails with `0x80070002`. + - **When User Account Control is off,** Windows ignores per-user COM registrations. `Diagnose()` now says so and checks the machine-wide registration instead. +- **Fixed: the preview pane stayed blank or kept loading once the handler had loaded.** + - **Cause:** .NET hands COM a free-threaded object by default, so Explorer's calls reached the handler on the preview host's RPC worker threads. `DoPreview` therefore created the pane window on a thread with no message loop. Every call reported success, but the window never painted or answered a message. + - **Fix:** the handler now derives from `StandardOleMarshalObject`, so every call runs on the handler's own apartment thread, whose message loop the pane needs. `preview.log` records that thread for each `DoPreview`. + - **Verified on Windows** with a control: Microsoft's own PDF previewer, hosted by the same test, answers messages and paints. Before this fix our pane window did not answer within 3 s and never showed the rendered page. Now it answers at once and the rendered page is on screen. +- **Regression gate:** the *Windows preview handler* workflow now fails unless a standard user's per-user registration previews end to end: every call succeeds, the pane window answers messages, and a rendered page is painted. +- **No more "error in the Linkco PDF Preview Handler" from our own code:** + - an exception in the pane's message handling, timers or render delivery is logged and shown as a message in the pane. Before, it could reach WinForms and end the Windows preview host, which Explorer reports as that error; + - an exception that does end the host is now written to `preview.log` with its stack trace. +- **Own preview host process:** the handler now runs in its own `prevhost.exe`, under its own AppID `{1C0ADB7B-F017-4384-BF73-95AA5BC5D084}` with `DllSurrogate` set to `prevhost.exe`. Before, it ran in the preview host that Windows shares between all apps' preview handlers. Microsoft requires this for .NET preview handlers. In the shared host: + - another app's handler could take ours down with it, e.g. a crash, or another .NET runtime such as the .NET 8 handlers of PowerToys; + - Explorer reported that as "an error in the Linkco PDF Preview Handler". + + The app, the Setup EXE, the NSIS installer and the MSI all register this host, and uninstalling removes it. The registration schema went from 4 to 5, so existing installations re-register the next time Linkco PDF Editor starts. +- **Hardened COM entry points:** + - every method Explorer calls catches its own failures, including failures while .NET is still loading the code (a missing or broken framework assembly). This covers the constructors, the colour and font settings, `GetWindow`, `SetSite`, focus and keyboard handling; + - the background render thread can no longer end the host with an exception; + - a failed `SetParent` is logged. +- **Installers:** + - the NSIS installer now stops running preview hosts before replacing the DLL, so the old code can't stay loaded; + - it also repairs the installing user's own registration, which takes precedence over the machine-wide one and could still point at an older build or a deleted portable copy. +- **`diagnose-preview.ps1 -Repair`:** for the current user, unblocks the DLL and engine, re-registers the installed DLL, stops stale preview hosts, then prints the diagnosis. +- **More checks in `Diagnose()`:** + - which preview host the handler gets (own, or the old shared one), and whether its `DllSurrogate` is set; + - the installed .NET Framework 4.x release; + - any other app's `.pdf` preview handler, by name. The PowerToys PDF previewer is named with how to turn it off. + +### 4. About and version +- **Help ▸ About** now credits the developer: "Developer: Muhammad Bilal (Linkco)", in all interface languages. +- **Version 1.0.0** is used everywhere: the app, CLI, preview handler (assembly `1.0.0.0`, matching the NSIS and MSI registrations), Setup EXE, MSI and portable ZIP. + +### 5. Downloads +- `dist/release/LinkcoPDFEditorSetup.exe` +- `dist/release/LinkcoPDFEditorSetup-1.0.0-windows-x64.msi` +- `dist/release/LinkcoPDFEditor-1.0.0-windows-x64-portable.zip` + +--- + +## What's new in v0.6.0 + +v0.6.0 brings in every change from the upstream PdfCraft 0.6.0 release (75 changes) while keeping the Linkco PDF Editor name, branding, Windows integration and installers. + +### 1. Windows printing that keeps the window responsive +- The Print dialog opens straight away: printers (with their Ready / Paused / Offline / Error status) are listed in the background, and "Looking for printers…" shows until the list arrives. A printer you pick while it is still looking stays picked. The refresh button ("Check again") also runs in the background. +- **Print** closes the dialog at once. The sheets are rendered at the chosen 150 / 300 / 600 DPI and sent to the spooler on a worker thread, so a long document no longer freezes the window. "Sending to *printer*…" appears first, then the spooler's answer (or the error, for example an offline printer). +- Unchanged from v0.5.0: each sheet prints at 100% on the driver's closest paper size, with zero margins, landscape when the sheet is wide, hard-margin compensation and no console window. +- Upstream's alternative Windows print backend (`windows_print.ps1`) was not adopted, because Linkco's backend already covers the same behaviour plus printer status and the 3-tier printer detection. +- A scaled annotation appearance no longer prints larger than its rectangle. +- **Print dialog sized like a normal window:** the dialog now grows with the app window (to within 24 px of its edges, up to 1600 × 1200) instead of a fixed 820 px box with a 320 × 380 preview. The preview takes all the room beside the settings, which scroll when the window is short. In a 1400 × 900 window the preview pane is about 850 × 670 instead of 320 × 380. It is never smaller than before. +- **Sharp print preview:** + - Pages are rendered at exactly the size of the larger preview. + - Until that render arrives, the preview no longer shrinks a much larger on-screen page image into the pane. Shrinking it skipped pixels, because the renderer makes no mipmaps, so thin lines and small text broke up. The thumbnail is shown instead. + - The paper and pages are placed on whole screen pixels, so text isn't blurred across two pixels. + +### 2. Windows PDF file icon and licence files +- PDF files associated with Linkco PDF Editor now show a dedicated **PDF document icon** (a page with a PDF badge, in Linkco navy and crimson) instead of the app icon. It is embedded in `LinkcoPDFEditor.exe` as icon resource 2 and registered by the Setup EXE, the NSIS installer and the MSI (`DefaultIcon …,-2`). +- `LICENSE-MIT`, `LICENSE-APACHE`, `NOTICE` and `LICENSE-document.txt` (the icon's ISC notice) are now installed beside the executables by every installer and included in the portable ZIP. + +### 3. Editing, pages and forms +- **Combine Files:** a thumbnail grid of every page from every file, where pages can be rotated, removed and reordered before combining. +- **Column select** (Alt/Option-drag, or *Edit ▸ Column select*), and selecting and moving several kinds of page objects together. +- Rectangle, oval and polygon comments get a fill colour; exported images keep their transparency (JPEG cut-outs included). +- Fill & Sign improvements; white or pale text is edited on a dark box instead of vanishing on white; **Reduce File Size** shrinks office scans, drops images nothing draws, and never saves a bigger copy. +- Docking: Tools and Inspector panels can be grouped as tabs, split beside the PDF or floated. *View ▸ Reset panel layout* restores the default. + +### 4. Interface +- **Preferences ▸ Interface size** (Auto follows the desktop's text scaling). +- Keyboard shortcut key names are shown in the interface language. +- Precision touchpads scroll 1:1 with the fingers. +- **Polish** interface (17 languages in total), including the Linkco Home page strings. +- Portable mode keeps its own single-instance window, separate from an installed copy. + +### 5. Fixes and hardening +- Passwords with non-ASCII characters open encrypted files; text files saved as UTF-16 create correct PDFs. +- Redaction pattern fixes; search handles the Turkish dotted/dotless i and runs of whitespace. +- OCR recognises €, and its model path is checked; about 30 smaller fixes and several hardening changes for hostile files. +- Agent and automation control: `ui.resize`, `ui.focus`, `ui.quit` (shows the save prompt when there are unsaved changes), `inspect focused=true` and `ui.dock`. These are only available when the app is started with `--control`. + +### 6. Downloads +- `dist/release/LinkcoPDFEditorSetup.exe` +- `dist/release/LinkcoPDFEditorSetup-0.6.0-windows-x64.msi` +- `dist/release/LinkcoPDFEditor-0.6.0-windows-x64-portable.zip` + +--- + +## Highlights in v0.5.0 + +### 1. Official Linkco Brand Identity & Enterprise Home Dashboard +- Rebranded desktop application, CLI, WebAssembly target, and installers to **Linkco PDF Editor** by **Al Rawabet Commercial Services & Contracting Company W.L.L. (Linkco)**. +- Designed multi-resolution application icons (`.svg`, `.ico`, `.icns`, and 16 px–1024 px `.png`) featuring the Linkco 4-node connected network emblem on deep navy (`#01131C`) and crimson red (`#F22424`). +- Updated the **Home** welcome view (`crates/ui-egui/src/home.rs`) with the Linkco corporate header banner, 8 verified **Recommended Tools** (`Organize pages`, `Edit a PDF`, `Combine files`, `Compress a PDF`, `Export a PDF`, `Scan & OCR`, `Fill & Sign`, `Protect a PDF`), an `Open file` card, `View all tools →` navigation to all 19 tool groups, pinned folders, recent files list (`File ▸ Open Recent`), session tab restoration (`Reopen last session`), and command palette search (`Ctrl+K` / `⌘K`). +- Removed all legacy branding, community chat links, and third-party promotional links. + +### 2. Windows File Explorer PDF Preview Handler (`IPreviewHandler`) +- Added `LinkcoPdfPreviewHandler.dll` (`packaging/windows/PreviewHandler.cs`, CLSID `{D4E7B6A2-4C91-4E3A-9B12-7A8F5C3E1D20}`), an out-of-process Windows Shell `IPreviewHandler` COM server hosted by `prevhost.exe` (`{6d2b5079-2f0b-48dd-ab7f-97cec514d30b}`). +- Added `pdfcraft-cli preview` (`apps/pdfcraft-cli/src/main.rs`) for fast single-page preview rendering with structured status reporting (`OK`, `PASSWORD_REQUIRED`, `EMPTY_PDF`, `INVALID_PDF`, `RENDER_ERROR`, `IO_ERROR`). +- Supports multi-page navigation (`Prev` / `Next`, `PgUp` / `PgDn`, `Home` / `End`), zoom (`−` / `+` / `Fit`, `Ctrl`+Wheel, click-drag pan), Windows Explorer Light/Dark theme adaptation, and non-destructive registration that backs up and restores any previously registered PDF preview handler on uninstall. +- **Production hardening:** + - Pages are rendered at the Preview Pane's actual width × zoom (`pdfcraft-cli preview --width PX --max-px 4096`), DPI-aware, re-rendered when the pane grows, and capped so poster-sized pages can't exhaust memory in `prevhost.exe`. + - Registration is per user (`HKCU`, no administrator rights) and covers `.pdf`, `SystemFileAssociations\.pdf`, Linkco's own ProgIDs and the user's current default PDF app (`UserChoice` / `UserChoiceLatest`), but never browser ProgIDs that also open web pages (`MSEdgeHTM`, `ChromeHTML`, …). Every value it replaces is backed up and restored on uninstall. + - Linkco PDF Editor checks the registration in the background at every start and registers again only when the DLL was updated or moved or the default PDF app changed. Portable mode never writes to the registry. Set `LINKCO_NO_PREVIEW_REGISTRATION=1` to opt out. + - **Non-ASCII install paths:** the start-up check that decides whether to register again compares the DLL path in an ASCII-safe form (`PreviewHandlerDllKey`), because `reg.exe` can't print most non-ASCII text. Before, a path containing e.g. an Arabic Windows user name (`C:\Users\محمد\AppData\Local\Programs\…`, the per-user install location) never matched, so the app re-registered — a hidden PowerShell plus an Explorer association refresh — on every start. + - **Uninstall cleans up for every user.** The app registers per user, for each user who starts it, so the uninstallers remove that registration — restoring each user's previous preview and thumbnail handlers — from **every user profile on the PC**, not only the uninstalling user's, before deleting the DLL. Otherwise other accounts would be left with Explorer pointing at a deleted DLL (blank previews, even where another PDF app had a working one before). Signed-in users' registries are cleaned in place; the others are mounted from their `NTUSER.DAT`/`UsrClass.dat` for a moment and unmounted again. The MSI does this in a deferred custom action running as LocalSystem, the NSIS uninstaller and the machine-wide Setup EXE do it elevated; the Setup EXE also retries file deletes while Explorer releases the DLL. (The NSIS uninstaller's cleanup command was also shortened to fit NSIS's 1024-character string limit — the previous one was cut off and so never ran.) + - `ThreadingModel=Apartment` (the handler hosts WinForms), `DisableLowILProcessIsolation=1` (the handler starts `pdfcraft-cli.exe` and reads the PDF by path), and Mark-of-the-Web is removed from the DLL and CLI, so downloaded builds load. + - The handler logs to `%USERPROFILE%\AppData\LocalLow\LinkcoPdfPreview\preview.log` and cleans up its temporary PNGs. +- **PDF thumbnails in File Explorer:** the same DLL adds an `IThumbnailProvider` (CLSID `{3D8CDE4B-E969-481F-BEB0-5E3B98287416}`), so PDFs show their first page in Medium/Large/Extra large icon, Tiles and Content views — Windows has no built-in PDF thumbnails. It is registered on `SystemFileAssociations\.pdf` and Linkco's own ProgIDs only, which Explorer consults after the default app's ProgID and `.pdf`, so a thumbnail provider from Acrobat or another PDF app keeps priority. Windows runs it in its isolated thumbnail process; rendering happens in a short-lived `pdfcraft-cli.exe` (8 s timeout), and password-protected or damaged PDFs simply keep the normal icon. To turn thumbnails off, use Explorer's *Folder Options ▸ View ▸ Always show icons, never thumbnails*. +- **Troubleshooting:** run this in PowerShell to see which preview handler and thumbnail provider Explorer resolves for `.pdf`, the user's default PDF app, and both registrations: + ```powershell + $dll = "$env:ProgramFiles\Linkco\Linkco PDF Editor\LinkcoPdfPreviewHandler.dll" # or dist\release\… for a dev build + $t = [Reflection.Assembly]::Load([IO.File]::ReadAllBytes($dll)).GetType('LinkcoPdfPreview.LinkcoPdfPreviewHandler') + $t::Diagnose() + $t::RegisterPreviewHandler($dll) # re-register for the current user if it reports [NOT Linkco] + ``` + +### 3. Windows Printer Detection, Native Driver Properties & High-Resolution Printing (150 / 300 / 600 DPI) +- Implemented 3-tier Windows printer enumeration in `crates/print/src/spool.rs`: + 1. WMI/CIM `Win32_Printer` (`Get-CimInstance` / `Get-WmiObject`) + 2. `.NET` `System.Drawing.Printing.PrinterSettings::InstalledPrinters` + 3. Windows Registry `HKCU\Software\Microsoft\Windows NT\CurrentVersion\Devices` & `Windows /v Device` +- Detects local, USB, TCP/IP, WSD, and UNC network printers (plus driverless `lpstat -e` queues on Unix/CUPS), identifies the system default printer, and reports printer availability (`Ready`, `Printing`, `Paused`, `Offline`, `Error`) with an in-dialog refresh button and offline status warning. +- Added native printer driver `Properties…` (`rundll32 printui.dll,PrintUIEntry /e /n ` on Windows; CUPS `lpoptions -l` PPD option editor on Unix). +- Upgraded Print dialog preview sharpness (per-page raster scaling; reworked in v0.6.0, see "Print dialog sized like a normal window") and added high-DPI sheet rendering (`Session::render_print_sheets` at 150 / 300 / 600 DPI, default 300 DPI) for crisp Windows print output via `.NET` `PrintDocument` with `HardMarginX/Y` compensation. + +### 4. Content Editing, Multilingual Typography, Digital Signatures & Forms (`v0.4.0`–`v0.5.0`) +- **Direct Content Editing & Scripts (`crates/edit`, `crates/fonts`):** Multi-stream paragraph editing, grouped Form XObject figure selection and editing, Arabic shaping (`harfrust`) and bidirectional (`unicode-bidi`) Type 3 text rendering, Cyrillic/Greek/WinAnsi `0x80–0x9F` encoding, and Japanese CID/katakana font fallback. +- **Digital Signatures (`crates/sign`):** Native Windows Certificate Store (`CNG` via `rustls-cng`) signing alongside macOS Keychain and `.p12`/`.pfx` files, BER PKCS#12/PKCS#7 parsing, expanded RSA/PSS/ECDSA/Ed25519 algorithms, RFC 3161 `/DocTimeStamp` signature verification, and strict X.509 chain validation. +- **Forms, XFA & Fill & Sign (`crates/forms`, `crates/xfa`, `crates/ui-egui`):** Image signatures with automatic white-background removal and live corner resize handles, optional flatten Fill & Sign on save, localized date formats, bulk multi-field property editing, rotated `/MK /R` widget appearances, `/Opt` export values, and a full XFA FormCalc interpreter. +- **Rendering, Memory & GPU (`crates/cos`, `crates/render`, `apps/pdfcraft`):** Zero-copy file-backed PDF stream slices, zero-copy pixmap transfers, 1:1 texel page rasters with zoom tile retention, automatic OpenGL (`glow`) fallback on `wgpu` initialization failure, Windows primary-display GPU adapter selection, and Windows 11 multi-monitor DPI scaling fixes. +- **Localization (`crates/ui-egui/src/i18n`):** 16 interface languages — English, Arabic (`ar`, right-to-left), Japanese (`ja`), Brazilian Portuguese (`pt-br`), Spanish (`es`), Telugu (`te`), Czech (`cs`), Simplified Chinese (`zh-hans`), Traditional Chinese (`zh-hant`), French (`fr`), German (`de`), Italian (`it`), Russian (`ru`), Ukrainian (`uk`), Bulgarian (`bg`), and Hungarian (`hu`). + +### 5. Windows Installer, Portable Mode & Build Automation +- Added `build.py` and `installer.py` for automated Windows release builds and packaging: + - `dist/release/LinkcoPDFEditorSetup.exe` (supports both Administrator machine-wide installation to `C:\Program Files\Linkco\Linkco PDF Editor` and standard per-user installation to `%LOCALAPPDATA%\Programs\Linkco\Linkco PDF Editor`, Start Menu and optional Desktop shortcuts, Windows Installed Apps registration, and clean uninstallation preserving user settings by default). + - `dist/release/LinkcoPDFEditorSetup-0.5.0-windows-x64.msi` (WiX Toolset v5 MSI package with per-machine scope guard and bundled OCR models). + - `dist/release/LinkcoPDFEditor-0.5.0-windows-x64-portable.zip` (portable archive with `portable.txt` / `LinkcoPDFEditor.portable` marker support storing user data in `PdfCraftData\` beside the executable). + +### 6. Arabic Interface, One Window for Every PDF, Redaction Lists & Signing Improvements +Brings in the latest upstream engine work (42 changes), adapted to Linkco PDF Editor. +- **Arabic interface (العربية):** A complete Arabic catalog (Edit ▸ Preferences… ▸ Language, Ctrl+, — or automatic on an Arabic Windows display language) with right-to-left menus and labels, Arabic plural forms and Arabic month and weekday names. Arabic glyphs come from Noto Sans Arabic (embedded by builds made with craft-fonts — `build.py` and `installer.py` now fetch it automatically) or from Windows' Segoe UI. Arabic file names and document titles are drawn in the correct order in tabs, recent files and Properties. +- **One window for every PDF (Windows):** Double-clicking PDFs in File Explorer, opening Outlook attachments or using Open With while Linkco PDF Editor is running now opens them as tabs in the existing window, instead of starting a new window each time. One instance runs per Windows sign-in (so Remote Desktop users stay separate); `LinkcoPDFEditor.exe --new-window file.pdf` still forces a separate window. The hand-off socket lives in `%LOCALAPPDATA%\Linkco PDF Editor\` beside the crash-recovery folder; portable copies always open their own window. +- **Sharper on mixed-DPI monitors:** The executable now declares Per-Monitor V2 DPI awareness in its Windows manifest, so moving the window between a laptop screen and an external monitor keeps text crisp. +- **Redaction:** Mark a whole list of words or phrases for redaction at once (one per line, or import a text file up to 1 MB), and stamp U.S. FOIA / Privacy Act exemption codes as redaction overlay text. +- **Digital signatures:** Sign and timestamp password-encrypted documents; smart cards and USB tokens in the Windows certificate store ask for their PIN; certificates whose key usage / extended key usage doesn't allow document signing, or that carry critical extensions the editor doesn't understand, are refused with a clear message; long digital ID names stay inside the picker. +- **Organize & create:** Build bookmarks from a tagged document's headings; Extract pages gets a File name field; images made into a PDF keep their ICC colour profile; print-sized TIFF images (up to 2 GiB of decoded data) can be converted. +- **Rendering accuracy:** Pages with `/UserUnit` (large-format engineering drawings) are shown at their real size in points, as in Acrobat; text rotated at any angle is selected and searched along its own baseline; PDF/A conversion no longer adds an sRGB output intent to CMYK documents. +- **Interface fixes:** Shortcuts show Ctrl (not ⌘) on Windows in the View menu, tooltips and Keyboard shortcuts; side panels keep their width after a window resize; the command palette closes on an outside click; when GitHub rate-limits update checks, Help ▸ Check for updates says when to try again. +- **Speed & robustness:** Obsolete in-flight page renders are cancelled when you scroll or zoom, the render pool survives metadata edits, and malformed annotation colours, field flags and font descriptor flags are handled safely. +- **Windows diagnostics:** The log now records the desktop renderer (GPU adapter, `wgpu`/OpenGL) at startup, which helps diagnose display problems (`PDFCRAFT_RENDERER=gl` still forces OpenGL). + +--- + +## Licensing & Notices + +Linkco PDF Editor is dual-licensed under the **Apache License, Version 2.0** (`LICENSE-APACHE`) and the **MIT License** (`LICENSE-MIT`). Third-party asset and library notices are provided in `NOTICE` and `ATTRIBUTION.md`. diff --git a/ROADMAP.md b/ROADMAP.md index 9e528c6203..f659bfdf6e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -233,7 +233,7 @@ Newest first: the date, what moved, and the new overall estimate. - **2026-10-07 (community, #161):** The "Save changes?" prompt keeps a long file name inside the modal: the title wraps to the dialog width, so the centered panel no longer stretches past the viewport, clips its message and pushes Save/Cancel off-screen (Windows report). The password prompt's file-name line wraps the same way, and a regression test pins the title and all three buttons inside a 1365×719 screen. Parity counts unchanged; ≈ 30–35%. - **2026-10-07 (community, #143):** Windows MSI gets a full-UI welcome dialog with a "Create a desktop shortcut" checkbox (on by default; `INSTALLDESKTOPSHORTCUT=0` for unattended installs), progress, files in use, repair/remove, and a "Setup completed successfully" screen with Finish (plus distinct failed/cancelled screens). Start Menu and desktop shortcuts are now plain links to `pdfcraft.exe` instead of advertised MSI shortcuts. Packaging checks the compiled MSI's shortcut, checkbox and dialog tables; the ARM64 smoke test checks both links' targets, their removal on uninstall, and the opt-out. Installer polish only; feature counts unchanged. ≈ 30–35%. - **2026-10-07 (localization):** The interface translates through the same system as PhotoCraft: one TSV catalog per language (`crates/ui-egui/src/i18n/ja.tsv`), the `tl!` macro, entries keyed by command id or with plural forms, and catalog tests (format, duplicates, placeholders, command ids). Catalogs are validated strictly (unknown escapes, reserved contexts, placeholders, ellipses, plural forms), a bad line is skipped and logged at run time, `fmt` substitutes in one pass, the drawing language is per thread, and each `.tsv` is an attributed asset (`kind = "translation"`, checked by `cargo xtask assets`); validation, attribution and the language-switch control test folded in from #175. The 49 existing Japanese strings moved over unchanged, plus `Auto`. The `language` preference now defaults to `auto` (follow the system language; English when it has no catalog); `en`/`ja` still persist, and unknown values are rejected. Not covered: dialogs and panels, Windows system-language detection. ≈ 30–35% (unchanged). -- **2026-10-07 (session 16):** PrintCraft is renamed PdfCraft: repo `storytold/pdfcraft`, crates and binaries `pdfcraft*`, bundle id `ai.storyteller.pdfcraft`. On first launch the app moves the old PrintCraft settings and crash-recovery folders to the new name, so upgrades keep recent files, preferences and unsaved work. No feature change. ≈ 30–35%. +- **2026-10-07 (session 16):** The legacy application is renamed: crates and binaries `pdfcraft*`, bundle id `ai.storyteller.pdfcraft`. On first launch the app moves the old settings and crash-recovery folders to the new name, so upgrades keep recent files, preferences and unsaved work. No feature change. ≈ 30–35%. - **2026-10-07 (community, #163):** Fill & Sign shows saved signature/initials previews with add, change and remove controls in the quick picker and left panel. The editor loads the saved typed text or drawn strokes; Apply replaces future placements and Cancel preserves the saved value. Existing annotations stay unchanged. Long typed names shrink to the placement width and include glyph overhangs in preview/PDF bounds. Regression coverage includes persistence, removal/recreation, long names and the opt-in UI control channel. Parity counts and effort estimate unchanged (50.2% shipped, ≈ 30–35% effort). - **2026-10-07 (fork, default-workspace-mode):** Preferences ▸ Documents and view remembers the workspace used for newly opened PDFs. All Tools remains the default; explicit CLI/control mode overrides last for the session and PDF Initial View metadata stays independent. Overall estimate unchanged (≈ 30–35%). - **2026-10-07 (community, M14, #112):** Simplified Chinese (简体中文, `zh-hans`) as a catalog of about 1,600 entries; `zh`, `zh_CN` and `zh-Hans` locales follow it. In Simplified Chinese the craft-fonts `Hans` faces come before the Japanese ones, so Simplified-only characters don't sit on a different baseline. @@ -275,7 +275,7 @@ Newest first: the date, what moved, and the new overall estimate. - Bookmark editing and page numbering (Number pages), with undo, agent tools and UI. - A render watchdog: pathological pages are skipped after 20 s instead of spinning forever. - The agent control channel no longer reports success when the window is hidden. - - Community links: Discord button in the title bar, plus Home, About, Help menu, CLI and README. + - External links: Help menu, About dialog, Home screen, and CLI. - Overall ≈ 10%. - **2026-10-01 (session 6):** - UI control channel: agents can inspect the widget tree, click, type, press keys, run commands and take screenshots of the running app. Off unless the app is started with `--control`; loopback only, token-authenticated. diff --git a/apps/pdfcraft-cli/build.rs b/apps/pdfcraft-cli/build.rs index ee77f13f6a..93842a149c 100644 --- a/apps/pdfcraft-cli/build.rs +++ b/apps/pdfcraft-cli/build.rs @@ -13,9 +13,10 @@ fn main() { return; } let mut res = winresource::WindowsResource::new(); - res.set("ProductName", "PdfCraft") - .set("FileDescription", "PdfCraft command-line tool") - .set("LegalCopyright", "Copyright (c) the PdfCraft contributors. MIT OR Apache-2.0.") + res.set("ProductName", "Linkco PDF Editor") + .set("CompanyName", "Al Rawabet Commercial Services & Contracting Company W.L.L.") + .set("FileDescription", "Linkco PDF Editor command-line tool") + .set("LegalCopyright", "© Al Rawabet Commercial Services & Contracting Company W.L.L. MIT OR Apache-2.0.") .set("OriginalFilename", "pdfcraft-cli.exe") .set("InternalName", "pdfcraft-cli"); if let Err(e) = res.compile() { diff --git a/apps/pdfcraft-cli/src/main.rs b/apps/pdfcraft-cli/src/main.rs index db61d46e6b..de23576bce 100644 --- a/apps/pdfcraft-cli/src/main.rs +++ b/apps/pdfcraft-cli/src/main.rs @@ -48,6 +48,7 @@ const USAGE: &str = concat!( "\ pdfcraft-cli info [--password PW] document summary as JSON pdfcraft-cli render --page N [--dpi 96] --out x.png (.png, .jpg, .tif or .pam) +pdfcraft-cli preview [--page N] [--dpi 150 | --width PX] [--max-px 4096] --out x.png [--password PW] pdfcraft-cli text [--page N] extracted text (pages separated by form feeds) pdfcraft-cli edit --out out.pdf [--rotate 1,3:90] [--delete 2,4] [--move 5:1] [--insert-blank 1] [--title T] [--author A] [--full] @@ -62,8 +63,7 @@ pdfcraft-cli run --script steps.json [--root DIR] [{\"tool\": \"doc_open mcp_usage!(), "\ pdfcraft-cli ui --control FILE [key=value …] [--out shot.png] - drive a running app started with --control FILE -help and feedback: https://discord.gg/artcraft" + drive a running app started with --control FILE" ); fn main() -> ExitCode { @@ -78,6 +78,7 @@ fn main() -> ExitCode { None => Err(format!("usage:\n{USAGE}").into()), Some("info") => info(&args[1..]), Some("render") => render(&args[1..]), + Some("preview") => preview(&args[1..]), Some("text") => text(&args[1..]), Some("edit") => edit(&args[1..]), Some("combine") => combine(&args[1..]), @@ -139,9 +140,7 @@ fn stdout_line(line: std::fmt::Arguments<'_>) -> Result<(), CliError> { } fn version() -> Result<(), CliError> { - stdout_line(format_args!("pdfcraft-cli {}", env!("CARGO_PKG_VERSION")))?; - stdout_line(format_args!("Discord: {} (help and feedback)", pdfcraft_engine::links::DISCORD))?; - stdout_line(format_args!("Web: {}", pdfcraft_engine::links::APP_PAGE))?; + stdout_line(format_args!("pdfcraft-cli {} (Linkco PDF Editor)", env!("CARGO_PKG_VERSION")))?; stdout_line(format_args!("Source: {}", pdfcraft_engine::links::GITHUB))?; Ok(()) } @@ -490,6 +489,76 @@ fn render(args: &[String]) -> Result<(), CliError> { Ok(()) } +/// Fast single-page preview helper used by the Windows File Explorer Preview Handler (`IPreviewHandler`). +/// Emits a single structured `STATUS\t...` line to stdout so the preview host can distinguish +/// valid PDFs, password-protected PDFs, empty PDFs, and damaged files without opening the main editor. +fn preview(args: &[String]) -> Result<(), CliError> { + let path = *positional(args).first().ok_or("preview: missing file")?; + let page: usize = flag(args, "--page").unwrap_or("1").parse::().unwrap_or(1).max(1); + let dpi: f32 = flag(args, "--dpi").unwrap_or("150").parse::().unwrap_or(150.0).clamp(36.0, 300.0); + // `--width PX` asks for a raster exactly as wide as the preview pane needs (the Explorer handler + // passes its pane width × zoom), overriding `--dpi`; `--max-px` caps the longer side so a poster- + // sized page can't allocate hundreds of megabytes in the preview host. + let width_px: Option = flag(args, "--width").and_then(|w| w.parse::().ok()).filter(|w| w.is_finite() && *w >= 1.0); + let max_px: f32 = flag(args, "--max-px").and_then(|m| m.parse::().ok()).filter(|m| m.is_finite()).unwrap_or(4096.0).clamp(64.0, 8192.0); + let out = flag(args, "--out").ok_or("preview: missing --out ")?; + let password = flag(args, "--password"); + + let bytes = match read(path) { + Ok(b) => b, + Err(e) => { + stdout_line(format_args!("STATUS\tIO_ERROR\t0\t{}", e.replace(['\r', '\n', '\t'], " ")))?; + return Ok(()); + } + }; + + let info = match inspect(bytes.clone(), password) { + Ok(i) => i, + Err(pdfcraft_render::OpenError::NeedsPassword | pdfcraft_render::OpenError::WrongPassword) => { + stdout_line(format_args!( + "STATUS\tPASSWORD_REQUIRED\t0\tThis PDF document is password-protected. Open it in Linkco PDF Editor to enter the password." + ))?; + return Ok(()); + } + Err(e) => { + stdout_line(format_args!("STATUS\tINVALID_PDF\t0\t{}", e.to_string().replace(['\r', '\n', '\t'], " ")))?; + return Ok(()); + } + }; + + let total_pages = info.pages.len(); + if total_pages == 0 { + stdout_line(format_args!("STATUS\tEMPTY_PDF\t0\tThis PDF document contains no pages."))?; + return Ok(()); + } + + let clamped_page = page.min(total_pages); + let scale = info.pages.get(clamped_page - 1).map_or(dpi / 72.0, |pi| preview_scale(pi.width, pi.height, dpi, width_px, max_px)); + let mut r = PageRenderer::new(bytes, RenderConfig { password: password.map(Arc::from), ..Default::default() }); + let p = r.render(RenderRequest { page: clamped_page - 1, kind: RequestKind::Pixels, tile: None, scale, tag: 0 }); + if let Some(e) = p.error { + stdout_line(format_args!("STATUS\tRENDER_ERROR\t{total_pages}\t{}", e.replace(['\r', '\n', '\t'], " ")))?; + return Ok(()); + } + + let png_bytes = pdfcraft_engine::export::encode_image(p.width, p.height, &p.rgba, ImageFormat::Png)?; + std::fs::write(out, png_bytes).map_err(|e| format!("{out}: {e}"))?; + stdout_line(format_args!("STATUS\tOK\t{total_pages}\t{clamped_page}\t{}\t{}", p.width, p.height))?; + Ok(()) +} + +/// Render scale (pixels per point) for `preview`: `--width` wins over `--dpi`, and the longer side +/// of the raster never exceeds `max_px`. Degenerate page sizes fall back to the `--dpi` scale. +fn preview_scale(page_w: f32, page_h: f32, dpi: f32, width_px: Option, max_px: f32) -> f32 { + let base = dpi / 72.0; + if !(page_w.is_finite() && page_h.is_finite()) || page_w <= 0.0 || page_h <= 0.0 { + return base; + } + let wanted = width_px.map_or(base, |w| w / page_w); + let cap = max_px / page_w.max(page_h); + wanted.min(cap).clamp(0.05, 300.0 / 72.0 * 4.0) +} + /// Child-process body for `check`: prints one JSON line. fn check_one(args: &[String]) -> Result<(), CliError> { validate_options("check-one", args, CHECK_ONE_OPTIONS)?; @@ -827,7 +896,24 @@ fn current_uid() -> u32 { #[cfg(test)] mod tests { - use super::control_file_problem; + use super::{control_file_problem, preview_scale}; + + #[test] + fn preview_scale_honours_width_dpi_and_the_pixel_cap() { + // Letter page, 612×792 pt. + assert!((preview_scale(612.0, 792.0, 144.0, None, 4096.0) - 2.0).abs() < 1e-4); + // `--width` overrides `--dpi`: 1224 px wide ⇒ 2 px per point. + assert!((preview_scale(612.0, 792.0, 72.0, Some(1224.0), 4096.0) - 2.0).abs() < 1e-4); + // The longer side is capped: 792 pt × scale ≤ 1000 px. + let capped = preview_scale(612.0, 792.0, 300.0, Some(10_000.0), 1000.0); + assert!(792.0 * capped <= 1000.0 + 1e-3, "{capped}"); + // A poster-sized page (A0) at 150 dpi stays within the cap. + let a0 = preview_scale(2384.0, 3370.0, 150.0, None, 4096.0); + assert!(3370.0 * a0 <= 4096.0 + 1e-3, "{a0}"); + // Degenerate sizes fall back to the dpi scale. + assert!((preview_scale(0.0, 792.0, 72.0, Some(500.0), 4096.0) - 1.0).abs() < 1e-4); + assert!((preview_scale(f32::NAN, 792.0, 72.0, None, 4096.0) - 1.0).abs() < 1e-4); + } #[test] fn a_control_file_must_be_yours_and_private() { diff --git a/apps/pdfcraft-cli/tests/preview.rs b/apps/pdfcraft-cli/tests/preview.rs new file mode 100644 index 0000000000..049ae3504c --- /dev/null +++ b/apps/pdfcraft-cli/tests/preview.rs @@ -0,0 +1,89 @@ +//! `preview` is the helper the Windows File Explorer preview handler (`LinkcoPdfPreviewHandler.dll`) +//! runs for every page it shows: it must always print one `STATUS\t…` line and exit successfully, +//! so the handler can show a friendly message instead of a generic failure. + +use std::path::{Path, PathBuf}; +use std::process::Command; + +const BIN: &str = env!("CARGO_BIN_EXE_pdfcraft-cli"); + +fn tmp(test: &str, name: &str) -> PathBuf { + let d = std::env::temp_dir().join(format!("pdfcraft-cli-preview-{test}-{}", std::process::id())); + std::fs::create_dir_all(&d).unwrap(); + d.join(name) +} + +fn fixture(test: &str) -> PathBuf { + let pdf = tmp(test, "in.pdf"); + let bytes = pdfcraft_engine::Session::new().create_from_text("Preview test", "Hello from the preview pane").unwrap(); + std::fs::write(&pdf, bytes.as_slice()).unwrap(); + pdf +} + +/// Runs `preview` and returns the tab-separated fields of its `STATUS` line. +fn preview(pdf: &Path, out: &Path, extra: &[&str]) -> Vec { + let mut args = vec!["preview", pdf.to_str().unwrap(), "--out", out.to_str().unwrap()]; + args.extend_from_slice(extra); + let r = Command::new(BIN).args(&args).output().unwrap(); + assert!(r.status.success(), "{}", String::from_utf8_lossy(&r.stderr)); + let stdout = String::from_utf8_lossy(&r.stdout).into_owned(); + let line = stdout.lines().find(|l| l.starts_with("STATUS\t")).unwrap_or_else(|| panic!("no STATUS line: {stdout:?}")); + line.split('\t').map(str::to_owned).collect() +} + +fn png_size(path: &Path) -> (u32, u32) { + let b = std::fs::read(path).unwrap(); + assert_eq!(&b[..8], b"\x89PNG\r\n\x1a\n"); + (u32::from_be_bytes([b[16], b[17], b[18], b[19]]), u32::from_be_bytes([b[20], b[21], b[22], b[23]])) +} + +#[test] +fn ok_status_reports_pages_and_raster_size() { + let pdf = fixture("ok"); + let out = tmp("ok", "p1.png"); + let s = preview(&pdf, &out, &["--page", "1", "--dpi", "72"]); + assert_eq!(s[1], "OK", "{s:?}"); + assert_eq!(s[2], "1"); + assert_eq!(s[3], "1"); + let (w, h) = png_size(&out); + assert_eq!((s[4].parse::().unwrap(), s[5].parse::().unwrap()), (w, h)); + assert!(w > 0 && h > w, "{w}×{h}"); +} + +#[test] +fn width_sets_the_raster_width_and_max_px_caps_it() { + let pdf = fixture("width"); + let out = tmp("width", "p1.png"); + let s = preview(&pdf, &out, &["--width", "400"]); + assert_eq!(s[1], "OK", "{s:?}"); + let (w, _) = png_size(&out); + assert!((399..=401).contains(&w), "{w}"); + + let s = preview(&pdf, &out, &["--width", "5000", "--max-px", "500"]); + assert_eq!(s[1], "OK", "{s:?}"); + let (w, h) = png_size(&out); + assert!(w.max(h) <= 501, "{w}×{h}"); +} + +#[test] +fn a_page_past_the_end_shows_the_last_page() { + let pdf = fixture("clamp"); + let out = tmp("clamp", "p.png"); + let s = preview(&pdf, &out, &["--page", "99", "--dpi", "36"]); + assert_eq!(s[1], "OK", "{s:?}"); + assert_eq!(s[3], "1"); +} + +#[test] +fn damaged_and_missing_files_get_a_status_not_a_failure() { + let bad = tmp("bad", "bad.pdf"); + std::fs::write(&bad, b"this is not a PDF").unwrap(); + let out = tmp("bad", "p.png"); + let s = preview(&bad, &out, &[]); + assert!(s[1] == "INVALID_PDF" || s[1] == "EMPTY_PDF", "{s:?}"); + assert!(!out.exists()); + + let missing = tmp("missing", "nope.pdf"); + let s = preview(&missing, &out, &[]); + assert_eq!(s[1], "IO_ERROR", "{s:?}"); +} diff --git a/apps/pdfcraft-cli/tests/version_resource.rs b/apps/pdfcraft-cli/tests/version_resource.rs index b680a32ad5..84be05dff1 100644 --- a/apps/pdfcraft-cli/tests/version_resource.rs +++ b/apps/pdfcraft-cli/tests/version_resource.rs @@ -33,9 +33,10 @@ fn the_exe_has_version_info_with_the_package_version() { let start = find(&exe, &utf16("VS_VERSION_INFO")).expect("no version resource"); let resource = &exe[start..]; for (key, value) in [ - ("ProductName", "PdfCraft"), - ("FileDescription", "PdfCraft command-line tool"), - ("LegalCopyright", "Copyright (c) the PdfCraft contributors. MIT OR Apache-2.0."), + ("ProductName", "Linkco PDF Editor"), + ("CompanyName", "Al Rawabet Commercial Services & Contracting Company W.L.L."), + ("FileDescription", "Linkco PDF Editor command-line tool"), + ("LegalCopyright", "© Al Rawabet Commercial Services & Contracting Company W.L.L. MIT OR Apache-2.0."), ("OriginalFilename", "pdfcraft-cli.exe"), ("InternalName", "pdfcraft-cli"), ("FileVersion", env!("CARGO_PKG_VERSION")), diff --git a/apps/pdfcraft-web/index.html b/apps/pdfcraft-web/index.html index 46b3a25e21..861e52359b 100644 --- a/apps/pdfcraft-web/index.html +++ b/apps/pdfcraft-web/index.html @@ -3,7 +3,8 @@ - PdfCraft + Linkco PDF Editor +