Skip to content

fix(edit): show backgrounds on pages that paint their own white backdrop - #2815

Open
alehel wants to merge 3 commits into
storytold:mainfrom
alehel:fix/background-hidden-by-page-backdrop
Open

alehel wants to merge 3 commits into
storytold:mainfrom
alehel:fix/background-hidden-by-page-backdrop

Conversation

@alehel

@alehel alehel commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

What this changes

A YouTube review showed Add Background "not working". It works on plain pages, but on a page that first fills itself with opaque white (browsers' Save as PDF, print drivers, many generators), the background is drawn behind that fill and is completely hidden. A near-white default colour ([1, 1, 0.85]) made it look broken even where it did work.

  • pdfcraft-edit: new backdrop module. Strict detection: one re, axis-aligned, opaque white in DeviceGray/RGB/CMYK, painted before anything else, covering the crop box (clip and ExtGState honoured). To replace it, that one fill operator becomes n in a per-page copy of its content stream, and the original stream object is left untouched for other pages that share it. The copy carries /PCBackdrop << /Original ref /At /Len >>, so Remove background restores the original, but only if the copy is still exactly what we wrote. An edit made since is kept. A page-sized picture (a scan) is reported only, never touched.
  • Background gains replace_backdrop (default on). The default colour is a light yellow that is visible on screen.
  • Dialog: shows "N pages paint their own white backdrop… Replace it" (ticked) and a warning for scanned pages. It checks 24 pages a frame, cached by doc id and edit generation, so long documents never stall it. The schematic preview now draws text lines over the colour.
  • Automation: doc_background takes replace_backdrop. New read-only doc_backdrops lists fill / image pages.

How you verified it

  • cargo fmt --check
  • clippy -D warnings on pdfcraft-edit, -engine, -automation, -ui-egui (--all-targets)
  • cargo test -p pdfcraft-edit (166), -p pdfcraft-automation (all suites), -p pdfcraft-ui-egui --test ui_group marks::, --test commands, engine background/marks
  • cargo xtask layers, cargo xtask assets, cargo xtask parity
  • Not run locally: wasm check (target not installed). CI covers it.

Tests, all seen failing with the fix reverted:

  • Unit (crates/edit/src/backdrop_tests.rs): replace and exact restore; a split across content streams; update-then-remove; a shared stream copied for one page only; an edited copy kept on remove; 19 not-a-backdrop cases left byte-identical (partial, clipped, grey, translucent, unknown gs, pattern, default black, painted-after, holes, non-rect paths, rotated, fill+stroke, Q underflow, short operands, 1e400); writer variants recognised (flipped Chrome-style CTM with clip, CMYK, sc, quarter turn).
  • End to end (crates/automation/tests/backdrop.rs): rendered pixels are white with replace_backdrop: false (the old bug) and red with it, through save/reopen; the scan page stays covered; Remove brings the backdrop back.
  • UI (ui_group/marks.rs): the offer and scan warning appear, unticking keeps the backdrop, ticking replaces it, and the offer is gone afterwards.
  • Also checked by eye in the app over the control channel: the white-backdrop page that stayed white before now shows the colour.

Never-crash

  • No new unwrap/expect/panic! outside tests
  • get() and checked conversions throughout. The scan is capped at 64 KiB and 4096 operators, q nesting at 64, and non-finite operands are rejected.
  • No unsafe
  • N/A: no crash fixed

Provenance

  • No assets, fonts or copied code
  • Behaviour from ISO 32000-2 (§8.5.3 path painting, n) and black-box testing of our own output. Acrobat's behaviour on such pages has not been observed, so the parity notes record this as our own choice.

Security

  • No new file paths (doc_backdrops reads none), no network, MCP unchanged

Parity and reach

  • edit.background-add / -update-remove evidence and notes updated, including what is still hidden: scans, backdrops inside a form XObject, non-rectangular or named-colour-space fills, and a preview that is still a schematic
  • Headless: doc_background replace_backdrop, doc_backdrops
  • ROADMAP progress log

Anything a reviewer should look at first

  • Default on. Replacing the backdrop edits the page's own content (in a copy), on by default in both the dialog and the tool. It is reversible through Remove and undo, and visually identical on white paper, but it is a content change the user didn't ask for by name. The dialog states it next to the checkbox.
  • Strictness of detection (walk in backdrop.rs). I chose to miss backdrops rather than ever neutralise real content. Backdrops inside a form XObject are the most likely real-world miss.
  • The default colour changed from [1, 1, 0.85] to [1, 0.95, 0.7].

🤖 Generated with Claude Code

alehel and others added 3 commits October 16, 2026 10:46
Add Background draws behind the page content, so on a page that first
fills itself with opaque white (browsers' Save as PDF, print drivers) the
background was hidden completely and the tool looked broken.

- pdfcraft-edit: new `backdrop` module. A strictly detected backdrop (one
  axis-aligned `re`, opaque white in a device colour space, painted before
  anything else and covering the crop box) is replaced by turning that one
  fill into `n` in a per-page copy of its stream; the original stream is
  left untouched for other pages. Remove background restores it, unless
  the copy was edited since. Page-sized pictures (scans) are reported only.
- Background gains `replace_backdrop` (default on); the default colour is
  a visible light yellow instead of near-white.
- Dialog: offers to replace the backdrop, warns about scanned pages,
  checks pages a few per frame, preview draws text over the colour.
- Automation: `doc_background` takes `replace_backdrop`; new read-only
  `doc_backdrops` lists pages with a backdrop.

Acrobat's behaviour on such pages is unobserved; recorded as our choice
in parity/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The six new dialog strings (the backdrop offer, its note, the scan
warning and "Checking pages…") were missing from every catalogue, which
the *_covers_ui_literals tests require. Languages with several plural
forms use the "label: {n}" pattern so any count reads correctly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 22 interface catalogues are registered assets; adding the Add
Background strings changed their SHA-256. Provenance is unchanged
(contributor-original translations).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant