@trupdf/annotations
40+ annotation types, XFDF round-trip, the interactive annotation canvas layer, undo/redo, threads + replies + status, measurement helpers, stylus input.
Core types
type AnnotationKind =
// Text markup
| 'highlight' | 'underline' | 'strikethrough' | 'squiggly'
// Notes / text
| 'sticky' | 'freetext' | 'callout' | 'typewriter' | 'caret'
// Shapes
| 'rectangle' | 'ellipse' | 'polygon' | 'polyline' | 'line'
| 'arrow' | 'arc' | 'cloud'
// Freehand
| 'ink' | 'pencil' | 'freehand-highlight' | 'handwritten-signature'
// Stamps
| 'stamp' | 'rubber-stamp' | 'image-stamp'
// Attachments
| 'file-attachment' | 'sound'
// Fields / redaction
| 'signature-field' | 'redaction-mark'
// Measurement
| 'distance' | 'arc-measurement' | 'perimeter' | 'area'
| 'rectangle-area' | 'ellipse-area' | 'count'
// Fill & sign quick marks
| 'check-mark' | 'cross-mark' | 'dot-mark' | 'date-stamp'
// Misc
| 'link' | 'image' | 'watermark' | 'reply';AnnotationManager
The single source of truth. UI components subscribe to events and derive view state — never duplicate the records.
const m = new AnnotationManager({ defaultAuthor: 'Reviewer' });
const id = m.add({ kind: 'highlight', page: 1, rect: …, quadPoints: … });
m.update(id, { color: { r: 1, g: 0.85, b: 0 } });
m.undo();
m.redo();
m.on('annotation.added', (a) => /* … */);Supporting classes: SelectionModel (multi-select),
AnnotationClipboard (copy/paste across pages), PresetStore
(per-tool style presets), CommandStack
(AddCommand/UpdateCommand/RemoveCommand/BatchCommand).
Wire formats
serializeXFDF(records)/deserializeXFDF(xml)— Acrobat-compatible.serializeJSON(records)/deserializeJSON(json)— REST API format.writeAnnotationDict/readPdfAnnotations— write and read annotations directly into / out of the PDF itself, so TruPDF-saved files render identically in Acrobat, Chrome, Firefox, Edge, and Apple Preview.
The XFDF emitter uses an Adobe-namespaced root with a trupdf:
extension for fields XFDF doesn't model (status, custom-data, font,
measurement units).
Annotation canvas layer
new FabricLayer({ pageNumber, manager, viewport, container }) mounts
the interactive annotation canvas onto a host <div>, subscribes to
manager events, and re-renders on
annotation.added/updated/removed/cleared. Coordinate helpers
(pdfToFabricPoint, pdfToFabricRect, fabricToPdfPoint) convert
between PDF user space and canvas space — never store canvas pixels in
XFDF.
Tool controller
ToolController drives interactive creation — ~50 tool kinds are
registered in TOOLS / TOOLS_BY_KIND, grouped into ribbon tabs
(annotation, shapes, insert, measure, redact, edit, fill-sign, forms)
via TOOL_MENUS / toolsForMenu. Bind to an annotation canvas layer
and call setTool('highlight') etc. Hotkey map exported as
TOOL_HOTKEYS. Legacy WebViewer tool names map via
legacyToolNameToKind / kindToLegacyToolName.
Measurement
calibrate(a, b, realValue, unit) → unitsPerPoint. Then
measureDistance / measurePerimeter / measureArea apply that
calibration in PDF user space. Arc helpers (arcLengthFromBezier,
circularArcLength, ellipsePerimeter, …) and formatting
(formatMeasurement, formatFractional) are exported alongside.
Stylus input
bindStylusInput(target, opts) with palm rejection, pressure, tilt,
twist, coalesced events. applyPressureCurve ships soft / linear / firm
curves.