Commit Graph
5 Commits
Author SHA1 Message Date
Brandon Thomas 61adb2063e Merge pull request #1306 from Hamza0101/reproducible-pdf-export
PDF export: SOURCE_DATE_EPOCH stands in for the clock, so exports repeat
2026-10-29 21:52:12 -04:00
Hamza 87b49d9973 PDF export: SOURCE_DATE_EPOCH stands in for the clock, so exports repeat
A PDF export recorded the second it was made in, so exporting one document
twice gave different files although the pages matched -- and the instance id
krilla derives from the bytes followed the timestamp, so nothing about the two
files was comparable.

SOURCE_DATE_EPOCH stands in for the clock when the export is given no date, as
the reproducible-builds specification defines it. A date passed in still wins,
and a value the PDF date format cannot hold -- malformed, negative, or past
the range -- is ignored rather than refusing the export or writing a date no
reader can parse. With the epoch pinned the two files are identical byte for
byte.

Rebased onto the post-split main: export_time and pinned_or live in
export/metadata.rs beside now_unix, which they stand in front of, and the call
site is in export/pipeline.rs. The ROADMAP keeps upstream's 2026-10-17 entry
with this one above it.
2026-10-28 19:09:25 +05:00
Dylan M. Taylor 07366af1b6 Refactor pdf for strict Clippy checks 2026-10-28 11:39:26 +00:00
NetterSilverandClaude Opus 5.5 1db1635a88 Ask the composition cache once per story and page in PDF export
The PDF exporter called Cache::get twice for every text frame it drew.
Each call rebuilds the cache signature of the whole story, which looks up
every frame of the story with Document::find (a linear walk over all
spreads), and the anchored-frame placements walk them again. For a story
threaded through many frames this is O(frames^2 x items) per export.

The document doesn't change during an export, so the exporter now keeps
the composition it got for each (story, page) and reuses it. The cache
still decides what to compose; the output is byte-identical.

Add examples/pdf_export.rs to designcraft-cli: File > Export PDF through
a headless session on the `designcraft-cli perf` stress document (200
pages, 1M characters in 40 threaded stories, 500 placed images). The
stress document generator moves unchanged from src/perf.rs to a small
library module (src/stress.rs) that the binary and the example share.

Ryzen 16 threads, Linux, 12 runs each, interleaved:
  main     median 3485 ms, min 3427 ms
  patched  median 2016 ms, min 1656 ms  (-42 % median, -52 % min)
The exported PDF is byte-identical (12,075,744 bytes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 16:47:25 +01:00
aiongg f33de8f4aa refactor(pdf): split export.rs into export/ 2026-10-26 21:00:23 +00:00