From 892f0b78f09ebdd4266b984613dffef365dbdd36 Mon Sep 17 00:00:00 2001 From: Joe Abou Serhal <80884927+joeabouserhal@users.noreply.github.com> Date: Sun, 11 Oct 2026 00:21:30 +0300 Subject: [PATCH] M14: give Windows PDF files a dedicated document icon (#890) * M14: give Windows PDF files a dedicated document icon Embed the document icon as resource 2 through the existing Windows resource build and select it in both PDF association registrations. Keep the asset reproducible and carry its required licence notices in Windows packages. Formatting, strict Clippy, 1,842 existing workspace tests, all 30 WASM crate checks, assets, layering and parity pass. The Windows x64 release package checks pass, and the contributor confirmed the icon in Explorer. Co-authored-by: Codex * Refresh catalog hashes after merging main --------- Co-authored-by: Codex Co-authored-by: Brandon Thomas --- ATTRIBUTION.md | 4 +++- ATTRIBUTION.toml | 22 ++++++++++++++++++ NOTICE | 4 ++++ apps/pdfcraft/build.rs | 5 ++++- assets/app-icon/LICENSE-document.txt | 31 ++++++++++++++++++++++++++ assets/app-icon/README.md | 8 +++++++ assets/app-icon/pdfcraft-document.ico | Bin 0 -> 35829 bytes assets/app-icon/pdfcraft-document.svg | 16 +++++++++++++ packaging/icons.sh | 20 ++++++++++------- packaging/windows/package.ps1 | 9 ++++++++ packaging/windows/pdfcraft.wxs | 18 ++++++++++++++- parity/acrobat-features.toml | 2 +- 12 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 assets/app-icon/LICENSE-document.txt create mode 100644 assets/app-icon/pdfcraft-document.ico create mode 100644 assets/app-icon/pdfcraft-document.svg diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 12a860e9..28bd17c7 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 (262) +## In this repository (264) | Asset | Title | Author | Licence | Source | Used for | |---|---|---|---|---|---| @@ -232,6 +232,8 @@ Every asset PdfCraft includes, bundles or uses to build its published material, | `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) | diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml index b7df46ac..e28d1527 100644 --- a/ATTRIBUTION.toml +++ b/ATTRIBUTION.toml @@ -2808,6 +2808,28 @@ kind = "icon" usage = "Embedded in pdfcraft.exe by apps/pdfcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab)" sha256 = "56daaaae9ae5389794909570885809adf5e1d9183bef2d9669ed2f9bba3ed6f5" +[[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)" +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" + +[[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)" +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" + [[asset]] path = "assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png" title = "PdfCraft app icon, 16 px" diff --git a/NOTICE b/NOTICE index 62e047ec..72184779 100644 --- a/NOTICE +++ b/NOTICE @@ -13,6 +13,10 @@ This product bundles third-party material under its own licenses, listed below. 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 + 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. - JetBrains Mono typeface (assets/fonts/JetBrainsMono-*.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-JetBrainsMono.txt. - Dancing Script typeface (assets/fonts/DancingScript.ttf), Copyright 2016 The Dancing Script Project Authors — SIL Open Font License 1.1 (Reserved Font Name "Dancing Script"). See assets/fonts/OFL-DancingScript.txt. diff --git a/apps/pdfcraft/build.rs b/apps/pdfcraft/build.rs index 2f61ed5c..35d519d9 100644 --- a/apps/pdfcraft/build.rs +++ b/apps/pdfcraft/build.rs @@ -1,5 +1,6 @@ //! Windows only: embed the app icon and version info (VERSIONINFO) into `pdfcraft.exe`, so it -//! shows in Explorer, the taskbar, the Start menu and Alt-Tab. +//! shows in Explorer, the taskbar, the Start menu and Alt-Tab. A separate PDF document icon +//! uses resource ID 2; the installer references it as `pdfcraft.exe,-2`. //! //! On every other target this does nothing. A missing resource compiler is a warning, so a //! cross-compile from macOS or Linux still links, unless `PDFCRAFT_REQUIRE_WINRES=1` turns it @@ -11,6 +12,7 @@ mod windows_manifest; fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=../../assets/app-icon/pdfcraft.ico"); + println!("cargo:rerun-if-changed=../../assets/app-icon/pdfcraft-document.ico"); println!("cargo:rerun-if-changed=src/windows_manifest.rs"); println!("cargo:rerun-if-env-changed=PDFCRAFT_REQUIRE_WINRES"); if std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") { @@ -18,6 +20,7 @@ fn main() { } let mut res = winresource::WindowsResource::new(); res.set_icon("../../assets/app-icon/pdfcraft.ico") + .set_icon_with_id("../../assets/app-icon/pdfcraft-document.ico", "2") .set_manifest(windows_manifest::WINDOWS_MANIFEST) .set("ProductName", "PdfCraft") .set("FileDescription", "PdfCraft PDF workbench") diff --git a/assets/app-icon/LICENSE-document.txt b/assets/app-icon/LICENSE-document.txt new file mode 100644 index 00000000..74b44ae1 --- /dev/null +++ b/assets/app-icon/LICENSE-document.txt @@ -0,0 +1,31 @@ +PdfCraft PDF document icon (pdfcraft-document.svg and pdfcraft-document.ico). +SPDX-License-Identifier: ISC AND (MIT OR Apache-2.0) + +The document outline and fold are adapted from Lucide file-text (lucide-static 1.49.0): +https://github.com/lucide-icons/lucide +The original is kept in assets/icons/file-text.svg. + +ISC License + +Copyright (c) 2026 Lucide Icons and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +The badge, outlined PDF lettering, colours and composition are original work +by the PdfCraft contributors. Copyright (c) 2026 PdfCraft contributors. +Licensed under either the MIT License or the Apache License, Version 2.0, +at your option. Full texts are LICENSE-MIT and LICENSE-APACHE at the +repository root, and beside this file in Windows distributions. + +The icon uses no typeface or external image. Regenerate the ICO with +packaging/icons.sh; every asset and its SHA-256 is recorded in ATTRIBUTION.toml. diff --git a/assets/app-icon/README.md b/assets/app-icon/README.md index 64eb9a30..10fb2d4c 100644 --- a/assets/app-icon/README.md +++ b/assets/app-icon/README.md @@ -33,6 +33,8 @@ Licence: [LICENSE.txt](LICENSE.txt) (`MIT OR Apache-2.0`, like the repo). | `pdfcraft-1024.png` | 1024 px on Apple's grid; also the runtime Dock icon on macOS | | `pdfcraft.icns` | macOS icon (16–1024 px) | | `pdfcraft.ico` | Windows icon (16–256 px), embedded in `pdfcraft.exe` by `apps/pdfcraft/build.rs` | +| `pdfcraft-document.svg` | Windows PDF file icon master: a Lucide document outline, green badge and outlined PDF lettering; no font dependency | +| `pdfcraft-document.ico` | Windows PDF file icon (16–256 px), embedded as resource 2 in `pdfcraft.exe` | | `hicolor/x/apps/ai.storyteller.pdfcraft.png` | Linux hicolor theme, 16–512 px; the 256 px one is the runtime icon on Windows and Linux | | `hicolor/scalable/apps/ai.storyteller.pdfcraft.svg` | Linux scalable icon (copy of the master) | @@ -40,6 +42,12 @@ Where it shows: `apps/pdfcraft/src/main.rs` sets the window icon (Dock, taskbar, Wayland app id `ai.storyteller.pdfcraft`; `packaging/linux/ai.storyteller.pdfcraft.desktop` names the hicolor icon. +Windows PDF files use resource 2 (`"pdfcraft.exe",-2`) when PdfCraft is chosen as the default +reader; the app keeps resource 1. The document outline is adapted from Lucide `file-text` +1.49.0 (ISC); its badge and outlined lettering are original (`MIT OR Apache-2.0`), covered by +[LICENSE-document.txt](LICENSE-document.txt). Both icons are embedded, requiring no runtime +sidecar. This provides a file type icon; first-page thumbnails still need a thumbnail provider. + ## Regenerate ```sh diff --git a/assets/app-icon/pdfcraft-document.ico b/assets/app-icon/pdfcraft-document.ico new file mode 100644 index 0000000000000000000000000000000000000000..79967a800a160bbd07727ab347a8f889cbdcbebf GIT binary patch literal 35829 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 + + + + + + + + + + + + + diff --git a/packaging/icons.sh b/packaging/icons.sh index e8b2c996..da8228ff 100755 --- a/packaging/icons.sh +++ b/packaging/icons.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -# Regenerate every app icon from assets/app-icon/pdfcraft.svg (the master vector). +# Regenerate the app icons from assets/app-icon/pdfcraft.svg and the Windows PDF file icon +# from assets/app-icon/pdfcraft-document.svg. Both are master vectors. # # Needs: resvg (brew install resvg / cargo install resvg) and python3 (stdlib only, for the .ico). # On macOS, iconutil also writes the .icns. The outputs are committed, so building and packaging @@ -39,13 +40,15 @@ done mkdir -p "$DIR/hicolor/scalable/apps" cp "$SVG" "$DIR/hicolor/scalable/apps/$ID.svg" -# Windows .ico: PNG-compressed entries, 16-256 px. -ICO_PNGS=() -for s in 16 20 24 32 40 48 64 128 256; do - render "$SVG" "$s" "$TMP/ico-$s.png" - ICO_PNGS+=("$TMP/ico-$s.png") -done -python3 - "$DIR/pdfcraft.ico" "${ICO_PNGS[@]}" <<'PY' +# Windows .ico: PNG-compressed entries, 16-256 px. The document icon has its own resource +# in pdfcraft.exe; the app icon remains the first/default icon. +for name in pdfcraft pdfcraft-document; do + ICO_PNGS=() + for s in 16 20 24 32 40 48 64 128 256; do + render "$DIR/$name.svg" "$s" "$TMP/$name-$s.png" + ICO_PNGS+=("$TMP/$name-$s.png") + done + python3 - "$DIR/$name.ico" "${ICO_PNGS[@]}" <<'PY' import struct, sys out, pngs = sys.argv[1], sys.argv[2:] blobs = [open(p, "rb").read() for p in pngs] @@ -58,6 +61,7 @@ for b in blobs: offset += len(b) open(out, "wb").write(head + entries + data) PY +done # macOS .icns. if command -v iconutil >/dev/null; then diff --git a/packaging/windows/package.ps1 b/packaging/windows/package.ps1 index c556652d..524280b9 100644 --- a/packaging/windows/package.ps1 +++ b/packaging/windows/package.ps1 @@ -87,6 +87,12 @@ $Stage = Join-Path $TargetDir "windows-package\$Arch" Remove-Item -Recurse -Force $Stage -ErrorAction SilentlyContinue New-Item -ItemType Directory -Force -Path $Stage | Out-Null Copy-Item (Join-Path $Bin 'pdfcraft.exe'), (Join-Path $Bin 'pdfcraft-cli.exe') $Stage +# The document icon embeds Lucide artwork: carry its ISC notice and the project licences +# beside the binaries in both distributions. +foreach ($f in 'LICENSE-MIT', 'LICENSE-APACHE', 'NOTICE') { + Copy-Item (Join-Path $Root $f) $Stage +} +Copy-Item (Join-Path $Root 'assets\app-icon\LICENSE-document.txt') $Stage & (Join-Path $PSScriptRoot 'sign.ps1') (Join-Path $Stage 'pdfcraft.exe') (Join-Path $Stage 'pdfcraft-cli.exe') @@ -122,6 +128,9 @@ $Portable = Join-Path $TargetDir "windows-package\pdfcraft-$Version-windows-$Arc Remove-Item -Recurse -Force $Portable -ErrorAction SilentlyContinue New-Item -ItemType Directory -Force -Path $Portable | Out-Null Copy-Item (Join-Path $Stage '*.exe') $Portable +foreach ($f in 'NOTICE', 'LICENSE-document.txt') { + Copy-Item (Join-Path $Stage $f) $Portable +} Copy-Item -Recurse $Models (Join-Path $Portable 'models') foreach ($f in 'README.md', 'LICENSE', 'LICENSE-MIT', 'LICENSE-APACHE') { $p = Join-Path $Root $f diff --git a/packaging/windows/pdfcraft.wxs b/packaging/windows/pdfcraft.wxs index 200800af..11d2e39a 100644 --- a/packaging/windows/pdfcraft.wxs +++ b/packaging/windows/pdfcraft.wxs @@ -70,10 +70,13 @@ PdfCraft entry to pick was the advertised Start Menu shortcut, which Windows can't run as a file handler ("This app can't run on your PC"). --> - + + + @@ -136,6 +139,19 @@ + + + + + + + + + + + + +