Phase 4 of NIGIG_PDF_FEATURE_PARITY_PLAN.md. ADR 0019.
Almost none of it existed: Outlines, PageLabels, EmbeddedFiles and
ViewerPreferences appeared nowhere in the workspace, in any crate. What did
exist was a builder whose central method was
pub fn add_page_with_content(&mut self, _width: f64, _height: f64, ...)
which accepted a page size and discarded it. Asking for 200x400 and 300x500
gave two US Letter pages, because no /MediaBox was written at all. The test
asserted the output contained the string "/Type /Page", which it did.
Two more defects sat in the object writer, both producing files our own
parser rejects: dictionary keys were written unescaped (a key with a space
reparses as "expected number"), and f64::NAN was emitted as the literal
token NaN, so one non-finite value anywhere made the document unreadable.
Added: outline trees with the open/closed state in the sign of /Count,
/PageLabels as a number tree with real roman and A..Z/AA..ZZ numbering,
named destinations, attachments with file specs, /Info, XMP, viewer
preferences, page mode and layout; AcroForm creation for text, checkbox,
radio, choice and signature fields with generated appearances; and
TrueType subsetting - DejaVu Sans goes from 759,720 bytes to 4,348 for
twelve characters.
cmap is deliberately not rebuilt: the subset is embedded as a CID font with
Identity-H, so the content stream addresses glyphs by id and /ToUnicode
serves extraction. A cmap disagreeing with the content stream is worse than
none. CFF is refused by name rather than emitting a font with no glyphs.
Nine real bugs, every one found by running the output through an
independent tool rather than by reading the code:
1 page size discarded reading a generated file back
2 dict keys unescaped probing the writer
3 NaN written as a keyword probing the writer
4 subset zeroed the lsb fontTools outline compare
5 hmtx indexed by new gid fontTools outline compare
6 name table format read as count BaseFont came out "Embedded"
7 add_font shifted numbers already handed out
8 trees allocated over font numbers - object 29 written twice
9 widgets missing /F Print, /P and appearance /Resources
7 and 8 are the instructive pair: every reference resolved and every object
existed, each simply named the wrong thing. pypdf reported correct field
values from a file PDFium rendered blank. 9 is the one only a renderer could
find - /F defaults to non-printable, and a form XObject naming a font its
/Resources does not declare is discarded whole.
Verified by three independent implementations: fontTools (0 outline
mismatches of 12 against the source font), pypdf (metadata, page sizes,
outline with resolved page numbers, all five fields, attachment
byte-for-byte, labels ['i','1']) and PDFium, which renders both pages
correctly. cargo run -p nigig-pdf-graphics --example generate_sample
regenerates the sample.
Fourteen mutations. Three survived and each exposed a weak test: the key
test used an attachment name (written as a string, never a key), nothing
read the outline open state, and /P could not be witnessed because
page_index is supplied by the reader, which already knows the page. All
three now killed.
pdf: 789 passed (was 730). pdf-ui: 775. Coverage 85.17%.