TPTruPDF

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

ToolWhat it does
edit-contentClick a text run to replace it inline (standard mode only)
add-paragraphClick to place a new paragraph
new-imageDrop 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:

  1. 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.
  2. 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.
  3. 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-stream re f operator 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:

  1. engine.applyContentEdits() — content-stream rewrites.
  2. Form back-write (AcroForm + XFA datasets).
  3. Annotation pass (XFDF embed / /Annot dict write).

The order is fixed so edits land before annotations — annotations can reference text runs that the edit pass moved or deleted.