diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml
index 489247559d..7dcd882f84 100644
--- a/ATTRIBUTION.toml
+++ b/ATTRIBUTION.toml
@@ -2879,7 +2879,7 @@ 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 = "27745c021830f82c033b0f15f2d8d9f8e099138743297887ff7e2c9e7ed069da"
[[asset]]
path = "assets/app-icon/pdfcraft-small.svg"
@@ -2890,7 +2890,7 @@ 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 = "b524df1a583f8034a5a23836955e4fb423e0149429d695e80d95e5056f408678"
[[asset]]
path = "assets/app-icon/pdfcraft-1024.png"
@@ -2901,7 +2901,7 @@ 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 = "68ac6730b8990d07503351d32eacea81e9ec171a7a6f09daf52d6555d8245c8a"
[[asset]]
path = "assets/app-icon/pdfcraft.icns"
@@ -2912,7 +2912,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "macOS app bundle icon"
-sha256 = "2425148222873de241d267aba667a8b234ecdd0149f2ca8bb6e79443b743b1e8"
+sha256 = "fca7e7a0e34cc5c5ecae5bca97ee896aac68c4a34b088bc3a0b3271484f23974"
[[asset]]
path = "assets/app-icon/pdfcraft.ico"
@@ -2923,7 +2923,7 @@ 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 = "709271d66e07710a3f785ea21b0c85c5228eaf8bebe5058bc0f71f9ef20749eb"
[[asset]]
path = "assets/app-icon/pdfcraft-document.svg"
@@ -2934,7 +2934,7 @@ 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 = "c129f1b538ce16e3c3fa0d89d3301038c51249ba5d61bfd98c46e69cfdf5c316"
[[asset]]
path = "assets/app-icon/pdfcraft-document.ico"
@@ -2945,7 +2945,7 @@ 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"
+sha256 = "910be5e0ecdc94ce00368077ca1bef449bd5d62a75516feeb37884296c6fac4d"
[[asset]]
path = "assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png"
@@ -2956,7 +2956,7 @@ 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 = "660d2aace45ec1a28bc7e3708eab71ffee5cb1203f57a6256f7bd7c727193567"
[[asset]]
path = "assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png"
@@ -2967,7 +2967,7 @@ 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 = "1989441bdcc8d1df0d73cfe7eb836e9211abaa0fd7fd6ec7e4634bfcd472995d"
[[asset]]
path = "assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png"
@@ -2978,7 +2978,7 @@ 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 = "7fd1ac555f7f6b13ef3fba2696dfb86900cfcb7f7b669aece38590bf2306cf2e"
[[asset]]
path = "assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png"
@@ -2989,7 +2989,7 @@ 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 = "784ef3bd9f9e479cb2df22a0aee259a441a9c358390e646639c3a0ed79d41288"
[[asset]]
path = "assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png"
@@ -3000,7 +3000,7 @@ 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 = "deb1a9f849549d3f0652fb6d3c30b6eb6ea54498eaea8c1007d901bbafe7067c"
[[asset]]
path = "assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png"
@@ -3011,7 +3011,7 @@ 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 = "1933bbeaea290497facd328e917dafcc433d0c0caa9f1e207aa45ac1e430898c"
[[asset]]
path = "assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png"
@@ -3022,7 +3022,7 @@ 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 = "47094c09fb77eb35d465eee46445626a4d78c7ef50629cc7d04a602de3e144e9"
[[asset]]
path = "assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png"
@@ -3033,7 +3033,7 @@ 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 = "dea8010a8b41011aba054d3bfb8b790da57bc958c60869f508e1bbd288d3f280"
[[asset]]
path = "assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg"
@@ -3044,7 +3044,7 @@ 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 = "27745c021830f82c033b0f15f2d8d9f8e099138743297887ff7e2c9e7ed069da"
[[asset]]
path = "docs/images/pdfcraft-bookmarks.png"
@@ -3341,7 +3341,7 @@ 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"
+sha256 = "182663e4d1c4fabbb7ab2e1f0d4e991a8e0859b4a8dee6934d3e25d77ea020af"
[[asset]]
@@ -3353,7 +3353,7 @@ 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"
+sha256 = "bedf1b23707b9e34157440e83f65464ff314fa9f6b1d39c7a8930d1645c2f8be"
[[fetched]]
file = "text-detection.onnx"
diff --git a/CLAUDE.md b/CLAUDE.md
index f51a96d56e..cd1b5b284a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -22,6 +22,7 @@ PdfCraft is a clean-room, open-source, Rust-native PDF application targeting Ado
- **Privacy.** When observing Acrobat, use synthetic fixtures only. Never capture the Home view, recent files or account info. Capture by window id (`plan/acrobat/tools/`). Never commit Acrobat outputs, corpus files or personal data.
- **Layering.** Nothing below L7 depends on egui/winit/eframe/rfd (`plan/architecture.md` §3). `cos`/`filters`/`crypt`/`arlington` stay standalone.
- **Page input.** Page modules read `PagePointer` (`crates/ui-egui/src/page_pointer.rs`), never egui's raw pointer state (`hover_pos`, `interact_pos`, `latest_pos`, `press_origin`, button reads); `page_pointer::tests::page_modules_read_the_pointer_only_through_page_pointer` enforces it.
+- **Page cursor.** Page modules claim the cursor for what is under the pointer (`view.cursor.claim(Layer::…, icon)`, `crates/ui-egui/src/canvas/page_cursor.rs`), never set it (`set_cursor_icon`, `cursor_icon =`, `on_hover_cursor`); `document_area` sets it once, from the claim on the highest layer the active tool reaches. `page_pointer::tests::page_modules_claim_the_cursor_and_never_set_it` enforces it.
- **Fidelity.** The PDF object graph is the model. Preserve unknown data. Saves are incremental unless a full rewrite is required. Never silently drop or repair data without recording it.
- **Never panic.** Every PDF, script, MCP call, settings file and keystroke is untrusted input, and none of it may crash the app or lose the user's work. This outranks feature work. Return `Result` (the crate's error enum) and propagate with `?`, or fall back leniently and record it. In non-test code:
- No `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!` unless it is provably infallible, with a comment saying why.
@@ -39,6 +40,7 @@ PdfCraft is a clean-room, open-source, Rust-native PDF application targeting Ado
- **Rebasing is a review step, not a mechanical one.** Read every hunk you resolve, and the auto-merged hunks in the files you touched too — `main` moves fast enough that a file can change by hundreds of lines under a branch.
- **External PRs are held to safety, security and completeness before style.** Provenance first (no Adobe-derived asset, no committed font, no copied GPL/AGPL code, behaviour from the spec and not from reading another implementation), then no new panic path or `unsafe`, then `--root` confinement on every path including ones reached by nested dispatch, opt-in-only MCP and control channel, no new outbound network, then a headless `automation` tool, tests at the right zoom and an honest `parity/` entry. Provenance is the part a contributor cannot be expected to know, and the only part that cannot be undone after merge.
- **Quality gates** before every commit: `cargo fmt --check`, clippy with `-D warnings`, the tests, `cargo xtask layers`, `cargo xtask assets`, and the wasm check once `xtask ci` exists (M0).
+ - New workspace crates must include `[lints] workspace = true` in `Cargo.toml` to inherit `[workspace.lints]`. Production crate roots must declare the required crate-level lint attributes before modules or other crate items; crate-level `//!` documentation may precede them.
- **Scope builds and tests to the crates you touched** — `cargo clippy -p -j 2 --all-targets` and `cargo test -p -j 2`, under a `timeout`. A full `--workspace` build has locked up a development machine's CPU; it is CI's job and CI runs it on every PR. Run the workspace sweep locally only when you have a reason to and the machine is free.
- **Check for existing work before starting a fix or feature.** Search the issues and PRs, open and closed, with `gh issue list -R storytold/pdfcraft --state all --search ""` and the same with `gh pr list` (try a few phrasings), and check whether a merged fix is already on `main` (`git merge-base --is-ancestor origin/main`). If one is, the report is likely from an older build: say so rather than fixing it again. If an open PR covers it, review or build on that PR instead of opening a competing one. If an issue exists, reference it in the PR (`Fixes #123`).
- **Commits and PRs:** `main` is the only integration branch and is **never pushed to directly**. Branch from an up-to-date `main` as `/` (`feat/`, `fix/`, `docs/`, `chore/`, `refactor/`), one task id per commit (e.g. `M1.4: xref stream reader`), commit only green states, and open a PR into `main` using `.github/pull_request_template.md`. Merge only when CI is green.
diff --git a/Cargo.lock b/Cargo.lock
index b201da8413..8fd7c9133b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1178,17 +1178,17 @@ dependencies = [
[[package]]
name = "craft-docpath"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
[[package]]
name = "craft-fonts-build"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
[[package]]
name = "craft-i18n"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
dependencies = [
"fixed_decimal",
"icu_decimal",
@@ -1211,7 +1211,7 @@ dependencies = [
[[package]]
name = "craft-keymap"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
dependencies = [
"egui",
"serde",
@@ -1221,7 +1221,7 @@ dependencies = [
[[package]]
name = "craft-menu"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
dependencies = [
"craft-keymap",
"craft-quit",
@@ -1234,7 +1234,7 @@ dependencies = [
[[package]]
name = "craft-print"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
dependencies = [
"craft-winprint-gdi",
"miniz_oxide 0.9.1",
@@ -1247,7 +1247,7 @@ dependencies = [
[[package]]
name = "craft-quit"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
dependencies = [
"dispatch2",
"egui",
@@ -1258,7 +1258,7 @@ dependencies = [
[[package]]
name = "craft-ui"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
dependencies = [
"craft-fonts-build",
"craft-i18n",
@@ -1279,7 +1279,7 @@ dependencies = [
[[package]]
name = "craft-update"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
dependencies = [
"chrono",
"dunce",
@@ -4205,7 +4205,7 @@ dependencies = [
[[package]]
name = "pdfcraft"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"chrono",
"craft-update",
@@ -4229,7 +4229,7 @@ dependencies = [
[[package]]
name = "pdfcraft-a11y"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-content",
"pdfcraft-cos",
@@ -4241,7 +4241,7 @@ dependencies = [
[[package]]
name = "pdfcraft-annot"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"pdfcraft-cos",
@@ -4252,7 +4252,7 @@ dependencies = [
[[package]]
name = "pdfcraft-audit"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-content",
"pdfcraft-cos",
@@ -4263,7 +4263,7 @@ dependencies = [
[[package]]
name = "pdfcraft-automation"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"base64 0.23.1",
"flate2",
@@ -4285,7 +4285,7 @@ dependencies = [
[[package]]
name = "pdfcraft-cli"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"base64 0.23.1",
"pdfcraft-audit",
@@ -4303,11 +4303,11 @@ dependencies = [
[[package]]
name = "pdfcraft-compare"
-version = "0.14.0"
+version = "0.15.0"
[[package]]
name = "pdfcraft-content"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"pdfcraft-cos",
@@ -4315,7 +4315,7 @@ dependencies = [
[[package]]
name = "pdfcraft-cos"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"chrono",
"hayro-syntax",
@@ -4330,7 +4330,7 @@ dependencies = [
[[package]]
name = "pdfcraft-create"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"encoding_rs",
"hayro-syntax",
@@ -4338,6 +4338,7 @@ dependencies = [
"pdfcraft-cos",
"pdfcraft-fonts",
"pdfcraft-model",
+ "pdfcraft-xfa",
"png 0.18.1",
"thiserror 2.0.21",
"tiff",
@@ -4346,7 +4347,7 @@ dependencies = [
[[package]]
name = "pdfcraft-crypt"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"aes",
"md-5",
@@ -4358,7 +4359,7 @@ dependencies = [
[[package]]
name = "pdfcraft-edit"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"kurbo 0.13.1",
@@ -4373,7 +4374,7 @@ dependencies = [
[[package]]
name = "pdfcraft-engine"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"chrono",
"craft-docpath",
@@ -4414,14 +4415,14 @@ dependencies = [
[[package]]
name = "pdfcraft-export"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"flate2",
]
[[package]]
name = "pdfcraft-filters"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"flate2",
"proptest",
@@ -4431,7 +4432,7 @@ dependencies = [
[[package]]
name = "pdfcraft-fonts"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"harfrust",
"pdfcraft-cos",
@@ -4441,7 +4442,7 @@ dependencies = [
[[package]]
name = "pdfcraft-forms"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"pdfcraft-content",
@@ -4454,11 +4455,11 @@ dependencies = [
[[package]]
name = "pdfcraft-geom"
-version = "0.14.0"
+version = "0.15.0"
[[package]]
name = "pdfcraft-js"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"boa_engine",
"chrono",
@@ -4466,7 +4467,7 @@ dependencies = [
[[package]]
name = "pdfcraft-measure"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-annot",
"pdfcraft-content",
@@ -4479,14 +4480,14 @@ dependencies = [
[[package]]
name = "pdfcraft-model"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-cos",
]
[[package]]
name = "pdfcraft-ocr"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"ocrs",
"pdfcraft-fonts",
@@ -4497,7 +4498,7 @@ dependencies = [
[[package]]
name = "pdfcraft-optimize"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"image",
"pdfcraft-annot",
@@ -4512,11 +4513,11 @@ dependencies = [
[[package]]
name = "pdfcraft-oracle"
-version = "0.14.0"
+version = "0.15.0"
[[package]]
name = "pdfcraft-organize"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"pdfcraft-content",
@@ -4527,7 +4528,7 @@ dependencies = [
[[package]]
name = "pdfcraft-platform"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"async-channel",
"futures-lite",
@@ -4537,7 +4538,7 @@ dependencies = [
[[package]]
name = "pdfcraft-preflight"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"flate2",
"pdfcraft-content",
@@ -4548,7 +4549,7 @@ dependencies = [
[[package]]
name = "pdfcraft-print"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"craft-print",
"pdfcraft-content",
@@ -4560,7 +4561,7 @@ dependencies = [
[[package]]
name = "pdfcraft-redact"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-annot",
"pdfcraft-content",
@@ -4576,7 +4577,7 @@ dependencies = [
[[package]]
name = "pdfcraft-render"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"bytemuck",
"flate2",
@@ -4595,7 +4596,7 @@ dependencies = [
[[package]]
name = "pdfcraft-sign"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"aes",
"aws-lc-rs",
@@ -4631,11 +4632,11 @@ dependencies = [
[[package]]
name = "pdfcraft-testkit"
-version = "0.14.0"
+version = "0.15.0"
[[package]]
name = "pdfcraft-ui-egui"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"arboard",
"base64 0.23.1",
@@ -4687,7 +4688,7 @@ dependencies = [
[[package]]
name = "pdfcraft-web"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"eframe",
"egui",
@@ -4699,7 +4700,7 @@ dependencies = [
[[package]]
name = "pdfcraft-xfa"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"base64 0.23.1",
"image",
@@ -4713,7 +4714,7 @@ dependencies = [
[[package]]
name = "pdfcraft-xfdf"
-version = "0.14.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-annot",
"pdfcraft-cos",
@@ -7350,8 +7351,6 @@ dependencies = [
[[package]]
name = "vello_cpu"
version = "0.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d8ded630e8316bb94a55881256506d1f3b9947b5f66db8a7d32ca7ba02decd0"
dependencies = [
"bytemuck",
"glifo 0.1.1",
diff --git a/Cargo.toml b/Cargo.toml
index 99f9fa251b..64a3cf5b60 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.14.0"
+version = "0.15.0"
edition = "2024"
license = "MIT OR Apache-2.0"
rust-version = "1.95"
@@ -13,51 +13,51 @@ repository = "https://github.com/storytold/pdfcraft"
[workspace.dependencies]
# Shared frontend components; engines remain independent of egui.
-craft-ui = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", features = ["serde"] }
+craft-ui = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545", features = ["serde"] }
# Quit the macOS way (#1136): ⌘Q asks about unsaved changes, and closing quits through `terminate:`.
-craft-quit = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0" }
+craft-quit = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
# One menu definition for the native macOS menu bar and the in-window bar elsewhere.
-craft-menu = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0" }
-craft-keymap = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", default-features = false }
+craft-menu = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
+craft-keymap = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545", default-features = false }
# Shared system spooler; document composition remains in pdfcraft-print.
-craft-print = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0" }
+craft-print = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
# Whether a path stored in a document may be opened (GoToR link targets).
-craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0" }
-craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", features = ["egui"] }
+craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
+craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545", features = ["egui"] }
# internal
-pdfcraft-geom = { path = "crates/geom", version = "0.14.0" }
-pdfcraft-filters = { path = "crates/filters", version = "0.14.0" }
-pdfcraft-cos = { path = "crates/cos", version = "0.14.0" }
-pdfcraft-crypt = { path = "crates/crypt", version = "0.14.0" }
-pdfcraft-organize = { path = "crates/organize", version = "0.14.0" }
-pdfcraft-measure = { path = "crates/measure", version = "0.14.0" }
-pdfcraft-annot = { path = "crates/annot", version = "0.14.0" }
-pdfcraft-audit = { path = "crates/audit", version = "0.14.0" }
-pdfcraft-fonts = { path = "crates/fonts", version = "0.14.0" }
-pdfcraft-model = { path = "crates/model", version = "0.14.0" }
-pdfcraft-content = { path = "crates/content", version = "0.14.0" }
-pdfcraft-redact = { path = "crates/redact", version = "0.14.0" }
-pdfcraft-print = { path = "crates/print", version = "0.14.0" }
-pdfcraft-xfdf = { path = "crates/xfdf", version = "0.14.0" }
-pdfcraft-sign = { path = "crates/sign", version = "0.14.0" }
-pdfcraft-optimize = { path = "crates/optimize", version = "0.14.0" }
-pdfcraft-a11y = { path = "crates/a11y", version = "0.14.0" }
-pdfcraft-oracle = { path = "crates/oracle", version = "0.14.0" }
-pdfcraft-testkit = { path = "crates/testkit", version = "0.14.0" }
-pdfcraft-ocr = { path = "crates/ocr", version = "0.14.0" }
-pdfcraft-js = { path = "crates/js", version = "0.14.0" }
-pdfcraft-compare = { path = "crates/compare", version = "0.14.0" }
-pdfcraft-preflight = { path = "crates/preflight", version = "0.14.0" }
-pdfcraft-export = { path = "crates/export", version = "0.14.0" }
-pdfcraft-edit = { path = "crates/edit", version = "0.14.0" }
-pdfcraft-create = { path = "crates/create", version = "0.14.0" }
-pdfcraft-forms = { path = "crates/forms", version = "0.14.0" }
-pdfcraft-xfa = { path = "crates/xfa", version = "0.14.0" }
-pdfcraft-render = { path = "crates/render", version = "0.14.0" }
-pdfcraft-engine = { path = "crates/engine", version = "0.14.0" }
-pdfcraft-platform = { path = "crates/platform", version = "0.14.0" }
-pdfcraft-ui-egui = { path = "crates/ui-egui", version = "0.14.0" }
-pdfcraft-automation = { path = "crates/automation", version = "0.14.0", default-features = false }
+pdfcraft-geom = { path = "crates/geom", version = "0.15.0" }
+pdfcraft-filters = { path = "crates/filters", version = "0.15.0" }
+pdfcraft-cos = { path = "crates/cos", version = "0.15.0" }
+pdfcraft-crypt = { path = "crates/crypt", version = "0.15.0" }
+pdfcraft-organize = { path = "crates/organize", version = "0.15.0" }
+pdfcraft-measure = { path = "crates/measure", version = "0.15.0" }
+pdfcraft-annot = { path = "crates/annot", version = "0.15.0" }
+pdfcraft-audit = { path = "crates/audit", version = "0.15.0" }
+pdfcraft-fonts = { path = "crates/fonts", version = "0.15.0" }
+pdfcraft-model = { path = "crates/model", version = "0.15.0" }
+pdfcraft-content = { path = "crates/content", version = "0.15.0" }
+pdfcraft-redact = { path = "crates/redact", version = "0.15.0" }
+pdfcraft-print = { path = "crates/print", version = "0.15.0" }
+pdfcraft-xfdf = { path = "crates/xfdf", version = "0.15.0" }
+pdfcraft-sign = { path = "crates/sign", version = "0.15.0" }
+pdfcraft-optimize = { path = "crates/optimize", version = "0.15.0" }
+pdfcraft-a11y = { path = "crates/a11y", version = "0.15.0" }
+pdfcraft-oracle = { path = "crates/oracle", version = "0.15.0" }
+pdfcraft-testkit = { path = "crates/testkit", version = "0.15.0" }
+pdfcraft-ocr = { path = "crates/ocr", version = "0.15.0" }
+pdfcraft-js = { path = "crates/js", version = "0.15.0" }
+pdfcraft-compare = { path = "crates/compare", version = "0.15.0" }
+pdfcraft-preflight = { path = "crates/preflight", version = "0.15.0" }
+pdfcraft-export = { path = "crates/export", version = "0.15.0" }
+pdfcraft-edit = { path = "crates/edit", version = "0.15.0" }
+pdfcraft-create = { path = "crates/create", version = "0.15.0" }
+pdfcraft-forms = { path = "crates/forms", version = "0.15.0" }
+pdfcraft-xfa = { path = "crates/xfa", version = "0.15.0" }
+pdfcraft-render = { path = "crates/render", version = "0.15.0" }
+pdfcraft-engine = { path = "crates/engine", version = "0.15.0" }
+pdfcraft-platform = { path = "crates/platform", version = "0.15.0" }
+pdfcraft-ui-egui = { path = "crates/ui-egui", version = "0.15.0" }
+pdfcraft-automation = { path = "crates/automation", version = "0.15.0", default-features = false }
# pdf
hayro = "0.7.1"
@@ -91,6 +91,9 @@ web-time = "1.1"
unsafe_code = "forbid"
[workspace.lints.clippy]
+cognitive_complexity = "deny"
+too_many_arguments = "deny"
+wildcard_imports = "deny"
dbg_macro = "warn"
todo = "warn"
@@ -125,6 +128,7 @@ hayro-postscript = { path = "vendor/hayro-postscript" }
hayro-jbig2 = { path = "vendor/hayro-jbig2" }
lopdf = { path = "vendor/lopdf" }
vello_common = { path = "vendor/vello_common" }
+vello_cpu = { path = "vendor/vello_cpu" }
# The egui and winit crates below are pinned to immutable storytold git revisions (egui
# 6d518fc799681571963842f95b55a6b68431b15a, winit a517b3846ee8457d84ee4975110bfda6797c44dc).
# Only the retained `vendor/winit` and `vendor/egui-wgpu` copies are provenance for the app's
diff --git a/README.md b/README.md
index 1766e26ebb..9599a54844 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
-
+
PdfCraft
@@ -21,10 +21,10 @@
-
-
-
-
+
+
+
+
diff --git a/apps/pdfcraft-cli/src/check.rs b/apps/pdfcraft-cli/src/check.rs
index 1821f85826..62993ad6dc 100644
--- a/apps/pdfcraft-cli/src/check.rs
+++ b/apps/pdfcraft-cli/src/check.rs
@@ -1,6 +1,8 @@
use super::commands::{parse_dpi, read};
use super::options::{AUDIT_OPTIONS, CHECK_ONE_OPTIONS, CHECK_OPTIONS, flag, positional, validate_options};
-use super::*;
+use super::{
+ Arc, CliError, Command, Duration, Instant, PageRenderer, Path, PathBuf, RenderConfig, RenderRequest, RequestKind, Stdio, inspect, stdout_line,
+};
/// Audit a document for faux redactions. Prints the findings as JSON; fails when any are
/// found so scripts and CI can gate on it, and when the audit itself cannot run.
diff --git a/apps/pdfcraft-cli/src/commands.rs b/apps/pdfcraft-cli/src/commands.rs
index 5efec8331c..9d0b2057f0 100644
--- a/apps/pdfcraft-cli/src/commands.rs
+++ b/apps/pdfcraft-cli/src/commands.rs
@@ -2,7 +2,7 @@ use super::options::{
COMBINE_OPTIONS, EXTRACT_OPTIONS, INFO_OPTIONS, RENDER_OPTIONS, SPLIT_OPTIONS, TEXT_OPTIONS, can_be_path_value, flag, needs_value, positional,
validate_options,
};
-use super::*;
+use super::{Arc, CliError, ImageFormat, PageRenderer, Path, PathBuf, RenderConfig, RenderRequest, RequestKind, Write, inspect, stdout_line};
pub(crate) fn read(path: &str) -> Result>, String> {
std::fs::read(path).map(Arc::new).map_err(|e| format!("{path}: {e}"))
diff --git a/apps/pdfcraft-cli/src/options.rs b/apps/pdfcraft-cli/src/options.rs
index ab1a3db34b..1ddbfabcd5 100644
--- a/apps/pdfcraft-cli/src/options.rs
+++ b/apps/pdfcraft-cli/src/options.rs
@@ -1,4 +1,4 @@
-use super::*;
+use super::CliError;
pub(crate) fn flag<'a>(args: &'a [String], name: &str) -> Option<&'a str> {
args.iter().position(|a| a == name).and_then(|i| args.get(i + 1)).map(String::as_str)
diff --git a/apps/pdfcraft-cli/src/run.rs b/apps/pdfcraft-cli/src/run.rs
index 19eed21876..0726087d9d 100644
--- a/apps/pdfcraft-cli/src/run.rs
+++ b/apps/pdfcraft-cli/src/run.rs
@@ -1,7 +1,9 @@
#[cfg(feature = "mcp")]
use super::options::MCP_OPTIONS;
use super::options::{RUN_OPTIONS, flag, positional, validate_options};
-use super::*;
+#[cfg(feature = "mcp")]
+use super::{Arc, Path, Write, automation_args};
+use super::{CliError, stdout_line};
// ---- automation --------------------------------------------------------------------------------
diff --git a/apps/pdfcraft-cli/src/ui.rs b/apps/pdfcraft-cli/src/ui.rs
index 9d12233528..dc419171b0 100644
--- a/apps/pdfcraft-cli/src/ui.rs
+++ b/apps/pdfcraft-cli/src/ui.rs
@@ -1,5 +1,5 @@
use super::options::{UI_OPTIONS, flag, positional, validate_options};
-use super::*;
+use super::{CliError, Duration, stdout_line};
// ---- UI control channel client -----------------------------------------------------------------
diff --git a/apps/pdfcraft-cli/tests/it/text.rs b/apps/pdfcraft-cli/tests/it/text.rs
index 3d39a9e284..b7fb2511b7 100644
--- a/apps/pdfcraft-cli/tests/it/text.rs
+++ b/apps/pdfcraft-cli/tests/it/text.rs
@@ -243,4 +243,40 @@ mod page_argument_tests {
assert_eq!(std::fs::read(&source).unwrap(), bytes);
}
}
+
+ #[test]
+ fn text_clips_glyphs_outside_the_crop_box() {
+ let dir = PageDir::new();
+ let path = dir.0.join("cropped.pdf");
+ let body = "BT /F1 12 Tf 20 260 Td (Outside header) Tj 0 -110 Td (Visible body) Tj 0 -120 Td (Outside footer) Tj ET";
+ let objs: Vec> = vec![
+ b"<< /Type /Catalog /Pages 2 0 R >>".to_vec(),
+ b"<< /Type /Pages /Kids [4 0 R] /Count 1 /MediaBox [0 0 200 300] >>".to_vec(),
+ b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>".to_vec(),
+ b"<< /Type /Page /Parent 2 0 R /CropBox [0 100 200 200] /Contents 5 0 R /Resources << /Font << /F1 3 0 R >> >> >>".to_vec(),
+ format!("<< /Length {} >>\nstream\n{body}\nendstream", body.len()).into_bytes(),
+ ];
+ let mut pdf = b"%PDF-1.7\n".to_vec();
+ let mut offsets = Vec::new();
+ for (i, o) in objs.iter().enumerate() {
+ offsets.push(pdf.len());
+ pdf.extend_from_slice(format!("{} 0 obj\n", i + 1).as_bytes());
+ pdf.extend_from_slice(o);
+ pdf.extend_from_slice(b"\nendobj\n");
+ }
+ let xref = pdf.len();
+ pdf.extend_from_slice(format!("xref\n0 {}\n0000000000 65535 f \n", objs.len() + 1).as_bytes());
+ for o in offsets {
+ pdf.extend_from_slice(format!("{o:010} 00000 n \n").as_bytes());
+ }
+ pdf.extend_from_slice(format!("trailer\n<< /Size {} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n", objs.len() + 1).as_bytes());
+ std::fs::write(&path, pdf).unwrap();
+
+ for args in [vec![], vec!["--page", "1"]] {
+ let out = Command::new(BIN).arg("text").arg(&path).args(&args).output().unwrap();
+ assert!(out.status.success(), "{args:?}: {out:?}");
+ assert!(out.stderr.is_empty(), "{args:?}: {}", String::from_utf8_lossy(&out.stderr));
+ assert_eq!(String::from_utf8(out.stdout).unwrap().trim(), "Visible body", "{args:?}");
+ }
+ }
}
diff --git a/assets/app-icon/README.md b/assets/app-icon/README.md
index 10fb2d4cf3..58ef07d37c 100644
--- a/assets/app-icon/README.md
+++ b/assets/app-icon/README.md
@@ -1,6 +1,6 @@
# PdfCraft app icon
-
+
**Creature:** a lion, in a frontal head-and-shoulders portrait, mane running off the bottom of the tile.
@@ -13,7 +13,7 @@ a full-bleed colour field, no frame or roundel, the animal looking at the viewer
|---|---|---|
| Ink | `#0b0b0c` | line work and the figure's contour |
| Paper | `#efe9dc` | the figure (the lion's silhouette) |
-| PdfCraft green (app colour) | `#12a58a` | the full-bleed field |
+| PdfCraft red (app colour) | `#b70228` | the full-bleed field |
**Tile:** `viewBox="0 0 512 512"`, a rounded square with `rx=112` that clips everything. Windows and Linux
icons use the full-bleed tile. macOS icons put it on Apple's grid (an 824 px body centred on a transparent
@@ -33,7 +33,7 @@ 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.svg` | Windows PDF file icon master: a Lucide document outline, red 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) |
diff --git a/assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png
index 20f4ca4393..b4ac96bc47 100644
Binary files a/assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png
index be76e69b86..c3f4315212 100644
Binary files a/assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png
index a00f8f9501..5ae21c7ded 100644
Binary files a/assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png
index be413a715a..766624ec8c 100644
Binary files a/assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png
index f9e2ef2b6e..ab6e8e9312 100644
Binary files a/assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png
index 73971ee5f9..55256b293d 100644
Binary files a/assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png
index 1d9ff4d11c..eb3699f9b8 100644
Binary files a/assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png b/assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png
index 14444f01bc..9bba411e39 100644
Binary files a/assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png and b/assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png differ
diff --git a/assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg b/assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg
index 3a1de9f076..5a8017ec4f 100644
--- a/assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg
+++ b/assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/app-icon/pdfcraft-1024.png b/assets/app-icon/pdfcraft-1024.png
index 3c79b60279..d6cf213765 100644
Binary files a/assets/app-icon/pdfcraft-1024.png and b/assets/app-icon/pdfcraft-1024.png differ
diff --git a/assets/app-icon/pdfcraft-document.ico b/assets/app-icon/pdfcraft-document.ico
index 79967a800a..ec1ea4568e 100644
Binary files a/assets/app-icon/pdfcraft-document.ico and b/assets/app-icon/pdfcraft-document.ico differ
diff --git a/assets/app-icon/pdfcraft-document.svg b/assets/app-icon/pdfcraft-document.svg
index 603a740157..b9d2fbf3c9 100644
--- a/assets/app-icon/pdfcraft-document.svg
+++ b/assets/app-icon/pdfcraft-document.svg
@@ -4,10 +4,10 @@