Skip to content

Write a markup annotation's comment as rich text - #110

Merged
bobsingor merged 1 commit into
embedpdf/mainfrom
embedpdf/feature/markup-rich-text
Nov 4, 2026
Merged

bobsingor merged 1 commit into
embedpdf/mainfrom
embedpdf/feature/markup-rich-text

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

/RC is an entry of every markup annotation (ISO 32000-2 §12.5.6.2, Table 171): the formatted text its popup shows. Only a free text draws it. Until now our rich text setters only wrote a free text, so a note's comment couldn't be written formatted, and an edited note kept Acrobat's old /RC next to its new /Contents.

  • EPDFAnnot_SetRichTextJSON and EPDFAnnot_SetRichTextXHTML now write any other markup annotation's comment (text, line, square, circle, polygon, polyline, the four text markups, caret, stamp, ink, file attachment, sound, redact, projection): /RC and its plain projection in /Contents, nothing else. No /DS, /DA or appearance, as Acrobat writes a note's.
  • The body states only what differs from a comment that states nothing (the reader's face, 12 pt, black, left-aligned). A comment written with the body it was read with comes back the same, and Acrobat's style-less notes stay style-less.
  • Links, popups and widgets are refused and left unchanged.

The writer (CPDF_RichTextWriter::ApplyComment, SerializeCommentRC) shares the envelope with the free text one; SerializeRC is unchanged.

Checked against Acrobat

text_rich_comment_acrobat.pdf is a note written by Acrobat 26: no body style, Enter as 
 inside a span, and font-size:-14.0pt on every span, a size nothing can be. We read it as rich text, the body's size kept, and writing it back reads the same, without the impossible size.

Tests

  • AcrobatNoteCommentReadsAsRichText: Acrobat's note reads as rc with its bold, underline and italic runs and its line breaks.
  • SetRichTextJSONWritesACommentAsAcrobatDoes: a note's exact /RC (no body style) and /Contents, no /DS, /DA or /AP; a square whose body differs states only its size and colour.
  • AcrobatCommentWrittenBackReadsTheSame: Acrobat's comment, read and written back, reads the same.
  • SetRichTextJSONRefusesKindsThatArentMarkup: a link and a popup are refused.
  • The two writing tests are recorded as layer-mode writers.

Three deliberate breaks in the new code each failed a test. On macOS the 203 annotation and rich text embedder tests pass. The engine's annotation conformance passes on the local engine (1923) and the cloud engine (1120) against a runtime built from this branch. The full suites and Linux CI haven't run yet.

Found on the way, not changed here: inside a layer document, writing to this fixture's note promotes no object into the layer. Upstream's FPDFAnnot_SetStringValue does the same, so it isn't new. The file keeps its objects in object streams, which may be why.

The engine side (richText on every markup kind, and a contents edit rewriting a formatted comment instead of leaving stale /RC) is on embedpdf/embed-pdf-viewer feature/markup-rich-text, which needs this released and pinned.

/RC is an entry of every markup annotation (ISO 32000-2 §12.5.6.2): the
text its popup shows. Only a free text draws it. EPDFAnnot_SetRichTextJSON
and EPDFAnnot_SetRichTextXHTML now write any other markup annotation's
/RC and its plain projection in /Contents, nothing else: no /DS, /DA or
appearance, as Acrobat writes a note's. The body states only what differs
from a comment that states nothing (the reader's face, 12 pt, black,
left-aligned), so a comment written with the body it was read with reads
back the same. Links, popups and widgets are refused.

Tests read Acrobat 26's note (text_rich_comment_acrobat.pdf: no body
style, Enter as 
 inside a span, an impossible font-size:-14.0pt on
every span), write a comment, write Acrobat's back, and refuse a link and
a popup.
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