mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-09 04:22:20 +00:00
* M5: a comment whose colour is written [r g b null] is drawn, as CMYK with the null read as 0 (view.render-annotation-appearances) ISO 32000-2 Table 166 /C (and /IC, Tables 178, 180, 181; /MK /BC and /BG, Table 192) is an array of 0, 1, 3 or 4 numbers whose length picks the colour space. A four-entry array with a non-number in it, such as [1 0 0 null] (PDFBOX-2699), made the /C parser give up, so a shape without an appearance stream was not drawn at all. PDFium, MuPDF and Poppler all read such an array as CMYK with the non-number as 0. - annot: a four-entry /C or /IC reads non-numbers as 0; other lengths still need every entry to be a number. - annot: the properties' fill uses the same parser (it read [r g b null] as RGB before), and /C no longer drops a non-number to make three numbers. - forms: /MK /BC and /BG read a four-entry array the same way instead of dropping the non-number and drawing RGB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn * M5: comment properties report the stroke colour as drawn; a reference among four colour entries is not read as 0 (view.render-annotation-appearances) props() reads a non-FreeText /C through the appearance parser, so a [1 0 0 null] stroke reports CMYK cyan as drawn, and grey and CMYK strokes report their converted colour. A reference among the four entries of a /C array (ISO 32000-2 7.3.10) is left unreadable instead of standing in as 0, so /C [1 0 0 6 0 R] is never drawn cyan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn * M5: re-run CI (fill_sign Escape test depends on the clock's second, passes locally) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn * M5: the comment list reports a comment's colour as drawn (view.render-annotation-appearances) summaries() accepted only a three-entry /C, so a Square with /C [1 0 0 null], drawn cyan and reported cyan by props(), had no colour in the comment list; grey and CMYK colours were dropped the same way. Non-FreeText comments now read /C through drawn_color (the array itself followed when it is given by reference), keeping the three-number fallback and the FreeText /DA handling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn * M5: the render inspector lists a comment's colour as drawn (view.render-annotation-appearances) The inspector accepted only a three-entry /C, with a referenced entry read as 0, so a /C [1 0 0 null], a grey or a CMYK colour listed none, unlike the comment list and the drawing. Non-FreeText comments now read /C by the appearance builder's rule (one entry grey, four CMYK with a non-number as 0 and a reference unreadable, finite and clamped), with the three-number fallback reading referenced entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn --------- Co-authored-by: mtlcl410 <chuanlin@niar.org.tw> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
pdfcraft-annot
Comments (annotations), ISO 32000-2 §12.5. Layer L3, depends on pdfcraft-cos, pdfcraft-fonts and pdfcraft-model.
What it does
- Builders for the comment types Acrobat's commenting tools create: sticky note (
Text+Popup), highlight, underline, strikethrough, squiggly, rectangle (Square), oval (Circle), line and arrow (Linewith/LE), freehand drawing (Ink) and text box (FreeText). - Appearance streams (
appearance::build) generated from the annotation dictionary, so new and restyled comments look the same in every viewer. Highlights multiply (/BM /Multiply). A line's leader lines (/LL,/LLE,/LLO) and caption (/Cap,/CP,/CO) are drawn as ISO 32000-2 Table 178 places them, the caption in black Helvetica 10. Note icons are PdfCraft's own drawings. Text boxes use standard Helvetica (WinAnsi), with line breaking by Helvetica's standard-14 metrics. Thai in a text box, callout or Fill & Sign text is shaped and drawn from the craft-fonts Thai face with Add text's writer (pdfcraft_fonts::shaped_text: Type 3 glyphs with a ToUnicode map), the box sized to the ink of its stacked marks and descenders; a build without a Thai face refuses it (AnnotError::Undrawable) instead of drawing?. Other text it can't draw (in a text box, callout, Fill & Sign text, line caption, measurement label or dynamic stamp's by-line;appearance::undrawable_text) is kept as typed and drawn as?, and the comment is marked with the first such character (pdfcraft_fonts::UNDRAWN_MARK) so the engine reports the edit and flattening refuses to make it permanent. Two refusals (AnnotError::Undrawable): a redaction mark's overlay text, which becomes page content when applied; and a restyle or resize of a comment another program drew with a font that has those characters, whose appearance is kept rather than redrawn with?(new text for it is taken). - Edits: reply (
/IRT), set review status (a/Statereply, as Acrobat's "Set status" does), change text, move, resize, restyle, delete (with pop-up and replies).
API sketch
let index = add_annotation(&mut doc, &NewAnnotation { page, shape, style, contents, author }, &meta)?;
add_reply(&mut doc, page, index, "Agreed", "Ada", &meta)?;
set_review_state(&mut doc, page, index, ReviewState::Accepted, "Ada", &meta)?;
move_annotation(&mut doc, page, index, dx, dy, &meta)?;
set_style(&mut doc, page, index, StyleChange::new(Some(rgb), Some(0.5), Some(2.0), None), &meta)?;
delete_annotation(&mut doc, page, index)?;
signature_image(&doc, page, index)?; // embedded image XObject of Fill & Sign signature/initials
A comment is addressed by (page, index in /Annots), the same pair
pdfcraft_render::Annotation reports. Meta carries the date and the /NM id so edits stay
deterministic; the engine supplies them.
Fidelity rules
- Unknown keys are kept. Inline annotation dictionaries are promoted to indirect objects only when an edit needs a reference to them.
set_stylerefuses (and changes nothing) when it cannot redraw the comment, e.g. stamps, cloudy borders or callouts, instead of leaving a stale appearance.- Replies get the parent's
/Rectand an empty appearance: they appear in comment lists but never paint a second icon. - Resizing a stamp changes its
/Rectand preserves its original appearance and resources; viewers scale that appearance into the new rectangle. Locked stamps refuse the edit. - Picture stamps (a natural-size or explicit-rectangle image, a PDF page, or an image
signature) and PdfCraft's rubber stamps counterrotate their appearance on rotated pages, so
the picture or label reads upright as the page is displayed. Restyling a picture stamp keeps
that appearance matrix. The rotation is the page's
/Rotateat placement. - Sticky notes and file attachments are not counterrotated: they carry the NoRotate flag and
their icon is drawn in an unturned 20 × 20 box. A viewer keeps them upright on a turned page,
about the upper-left corner of
/Rect(ISO 32000-2 §12.5.3). PdfCraft's renderer does so (vendored hayro-interpret patch 37), andSummary::no_rotatetells the UI where the icon is drawn.
Not yet
Callouts, polygons and polylines, clouds, carets (insert/replace text), stamps, file
attachments, rich text (/RC, /DS), and the shared named-appearance cache Acrobat writes.