Content editing
Insert paragraphs, insert images, and replace text inside the page
content stream — not as annotations. Edits bake before annotations
when SaveEngine.saveAll() flushes, so they survive any "include
annotations: false" toggle.
Tools
| Tool | What it does |
|---|---|
edit-content | Click a text run to replace it inline (standard mode only) |
add-paragraph | Click to place a new paragraph |
new-image | Drop a PNG / JPEG into the page |
edit-content is disabled in secure mode — replacement requires
reading the page's text content, which secure mode suppresses by
design. Insert Paragraph and Insert Image still work in secure mode
because they don't read existing content.
Programmatic API
For simple additive edits outside the viewer, applyEdits takes PDF
bytes plus a list of edits (coordinates in PDF user space,
bottom-left origin) and returns the new bytes:
import { applyEdits } from '@trupdf/viewer';
const out = await applyEdits(bytes, [
{ kind: 'text', page: 1, x: 100, y: 200, text: 'Inserted', font: 'Helvetica', fontSize: 12 },
{ kind: 'image', page: 3, x: 50, y: 100, width: 200, data: pngBytes, mime: 'image/png' },
{ kind: 'rect', page: 4, x: 40, y: 80, width: 120, height: 60, fill: { r: 1, g: 1, b: 1 } },
]);Text edits accept color, maxWidth (wraps longer text), and
rotate; image edits auto-scale height from width when omitted.
Interactive replace / delete flows go through the viewer's
content-edit engine (below), which owns detection and font
resolution.
Fonts
Edited and inserted text keeps the document's original typeface whenever possible:
- While editing, the inline editor and canvas preview render with the very font face the render engine loaded for the page (the embedded font program is registered with the browser), so entering edit mode does not visibly change the typography.
- On save, the edited text is drawn with the page's own font resource — encoded through the font's ToUnicode map — so the baked PDF shows the exact source typeface in Acrobat, Chrome, Firefox, Edge and Preview. This covers the composite subset fonts every Word/Office PDF uses. Where resource reuse isn't possible, the original embedded program is re-embedded (subset) via the font engine when it covers every glyph of the new text.
- Fallback: non-embedded fonts, Type3 fonts, or edits that
introduce glyphs the original font never mapped degrade to the
closest Standard 14 face —
Helvetica,TimesRoman,Courier×{regular, bold, italic, bold-italic}— chosen by the font matcher from the real PostScript name and the font's serif/monospace classifier flags. Text on this tier is sanitized against the face's character set so one stray glyph can never abort a save. Users can override the face at edit time.
Inserted paragraphs adopt the typography (family, size, weight, leading) of the nearest text block on the page — falling back to the page's dominant body style — so new text reads as part of the document.
Original-font reuse and re-embedding require extended font introspection (enabled automatically outside secure mode). The font engine is lazy-loaded on the first save that needs it — never on the viewer's critical path.
Removal
Removal goes through a pluggable removal adapter. Three ship:
ContentStreamRewriterAdapter(default) — true structural removal: the operators that draw the targeted text or image are blanked or deleted from the page content stream, so nothing masks and nothing lingers on coloured or patterned backgrounds.WhiteOutRemovalAdapter— masks the original bbox with a content-streamre foperator pair instead. Universally cross-viewer compatible because both operators are ISO 32000-2 §8 primitives; useful as a conservative alternative.PdfiumRemovalAdapter— the native-engine removal adapter, for hosts that run their own native PDF engine plumbing (e.g. a server-side bake). Currently a forward-compat stub that hosts subclass; the fully wired implementation lands with the Phase 8 redaction engine.
The bake pipeline is adapter-agnostic, so swapping is one option:
import { ContentEditEngine, PdfiumRemovalAdapter } from '@trupdf/content-edit';
const engine = new ContentEditEngine({ removal: new PdfiumRemovalAdapter() });Flush order
SaveEngine.saveAll runs three passes in order:
engine.applyContentEdits()— content-stream rewrites.- Form back-write (AcroForm + XFA datasets).
- Annotation pass (XFDF embed /
/Annotdict write).
The order is fixed so edits land before annotations — annotations can reference text runs that the edit pass moved or deleted.