Web API reference
Generated from the type declarations in the published package. For a guided introduction, start with the Web guide.
233 public members of PDFEditor, the 13 types declared next to it, and the package's 13 other exports (digital signatures and the engine loader), generated from the shipped .d.ts files.
Static members
create
static create(canvas: HTMLCanvasElement, opts?: PDFEditorOptions): Promise<PDFEditor>DEFAULT_MIN_ZOOM
static readonly DEFAULT_MIN_ZOOM = 0.5licenseInfo
static licenseInfo(opts?: { wasmUrl?: string; }): Promise<LicenseInfo>The current license verdict (loads the engine if needed).
MAX_ZOOM
static readonly MAX_ZOOM = 6refreshLicense
static refreshLicense(opts?: { wasmUrl?: string; }): Promise<LicenseInfo>Online keys: ask the license server now and resolve to the verdict afterwards. Offline keys resolve at once.
setLicenseKey
static setLicenseKey(key: string | null, opts?: { wasmUrl?: string; }): Promise<LicenseInfo>Set (or with null clear) the license key for this page. Resolves to the verdict.
VERSION
static readonly VERSION: stringThe SDK's version, stamped from package.json by scripts/gen-bindings.mjs — do not edit.
Instance members
abortPageRenders
abortPageRenders(): voidAbort any in-flight page raster. The header is specific about when: at the START of a new pinch, because the previous settle's crisp render is stale the moment a new gesture begins and letting it finish holds the engine lock against the gesture's first frames — the "cannot pinch again until the zoom settles" stall.
activePage
get activePage(): numberapplyEmbeddedFont
applyEmbeddedFont(name: string): booleanApply one of the document's own embedded fonts by name.
armReplace
armReplace(): voidbackspace
backspace(): voidbeginFieldDrag
beginFieldDrag(): voidLive field drag. mode 8 = move, 0-7 = a resize handle; deltas are TOTAL since begin.
beginTextEdit
beginTextEdit(x: number, y: number): booleanBegin editing the text LINE under a point (a double-click). Returns false if the point missed text, which is the shell's cue to treat the gesture as an ordinary tap.
beginTextEditOnSelection
beginTextEditOnSelection(): booleanOpen a session on the CURRENT selection, rather than at a point (the double-click path).
canPaste
get canPaste(): booleancanRedo
get canRedo(): booleancanRedoHere
get canRedoHere(): booleancanUndo
get canUndo(): booleanIs there anything to undo (resp. redo) ANYWHERE in the document?
canUndoHere
get canUndoHere(): booleanUndo/redo restricted to the page on screen — the engine's own rule, kept for a host that wants it.
caretOffset
get caretOffset(): numbercaretView
caretView(): { x: number; y: number; h: number; } | nullCaret position and height in canvas px, for drawing a host caret or an IME box.
caretViewAt
caretViewAt(off: number): { x: number; y: number; h: number; } | nullclearClipboard
clearClipboard(): voidclearFieldSelection
clearFieldSelection(): voidclearHover
clearHover(): voidDrop the hover outline — the pointer left, or something else took over.
clearMaterializedAnnots
clearMaterializedAnnots(): voidFinish restoring ALL note/sound glyphs on this page; clears their annotations and restoration history.
clipboardData
clipboardData(): Uint8Array<ArrayBuffer> | nullcommonKind
get commonKind(): numberThe kind every member of the selection shares, or -1 when they differ. The property bar should only offer a type's controls when this is >= 0 — otherwise a group of a text layer and an image gets a font picker.
consumePageOp
consumePageOp(): { kind: number; a: number; b: number; } | nullDid the last undo/redo replay a structural PAGE op, and what did it do? Page ops interleave with the content history, so an undo can change the page SET — the rail has to be told, or it shows pages that no longer exist.
consumeReplace
consumeReplace(): voidconsumeWrap
consumeWrap(): boolean1 once when typing WRAPPED to a new line, so the shell can react (scroll, resize).
contentDY
get contentDY(): numberThe live keyboard-lift offset in canvas px (<= 0 when lifted).
contentLift
get contentLift(): numberThe live keyboard-lift offset, the companion to contentDY.
copy
copy(): booleancurrentPageHasText
get currentPageHasText(): boolean0 = a scanned page with no selectable text — worth warning before a markup tool.
currentPageSizePoints
currentPageSizePoints(): { w: number; h: number; } | nullThe CURRENT page's size in points (pre-rotation source box).
cut
cut(): booleandebugFlags
get debugFlags(): numberdeleteField
deleteField(): booleandeletePage
deletePage(index: number): booleandeleteSelection
deleteSelection(): voiddeselect
deselect(): voiddestroy
destroy(): voiddisarmReplace
disarmReplace(): voiddocument
get document(): PDFDocumentEditorThe open document from code (the programmatic document API): read every layer, change and add them, fill forms, edit metadata and pages. Changes show at once and the user can undo them. Survives open() — it always addresses the document currently open.
documentPageSizePoints
documentPageSizePoints(): { w: number; h: number; } | nullThe document's own page size in points, independent of the render surface.
documentTextClass
documentTextClass(pdf: Uint8Array, password?: string): 'text' | 'scanned' | 'empty'What a WHOLE document is made of, for the heads-up at open time.
dragField
dragField(mode: number, dx: number, dy: number): voiddragScaleField
dragScaleField(factor: number): booleanScale the selected FIELD about its centre, uniformly.
duplicateField
duplicateField(): booleanduplicatePage
duplicatePage(index: number): booleaneditLayerHitsAt
editLayerHitsAt(x: number, y: number): booleanIs a point inside the EDITED layer's true oriented footprint?
editLineRect
editLineRect(): { x: number; y: number; w: number; h: number; } | nulleditSelRect
editSelRect(): { x: number; y: number; w: number; h: number; } | nullThe selected RANGE's rect, and the edited LINE's rect.
editText
editText(): stringThe edited paragraph's text. Empty outside a session.
embeddedFonts
embeddedFonts(): string[]The DISTINCT fonts already embedded on this page, by stripped BaseFont name. Applying one of these reuses the live font — no re-embed, no subset growth — which is why they belong at the top of any font picker rather than mixed in with system faces.
endFieldDrag
endFieldDrag(commit?: boolean): voidendTextEdit
endTextEdit(): voidfieldBorderWidth
get fieldBorderWidth(): numberfieldBoxAt
fieldBoxAt(x: number, y: number): HoverBox | nullThe box of the form field under a point, for a hover highlight in Form Editor — non-mutating, unlike selectFieldAt. Returns a HoverBox (device px, the space drawHover draws in) tagged with the field's kind, or null when no field is there. The engine returns the field's viewport rect the same way the selected-field ring reads it, so the highlight and the ring line up exactly.
fieldColor
fieldColor(which: 0 | 1 | 2): numberfieldHandleAt
fieldHandleAt(x: number, y: number): numberWhich field handle a point is on, in the FIELD convention, or 8 for the body, or -1.
fieldOutlineBoxes
fieldOutlineBoxes(): OutlineBox[]The same, for form-field widgets.
fillSelectedField
fillSelectedField(): numberExercise the SELECTED field in place — iOS's fillSelectedField (PDFEditorUI.swift ~11093), the first row of its widget menu. FormTap at the field's centre: a text field takes focus (type it), a combo/list focuses and the shell opens its option picker off the formfocuschange event, and a check box / radio toggles on the tap itself. Returns the field type, or -1 if nothing is selected.
flattenForms
flattenForms(): booleanBake every form field into page content — one undo step. Each field becomes a layer of its own that looks exactly like it did; nothing else on the page (comments, stamps) is touched.
formCommit
formCommit(): voidformFieldIsMultiline
get formFieldIsMultiline(): booleanformFieldOptions
formFieldOptions(x: number, y: number): string[]Options of a combo/list field at a point, for the shell's picker.
formFieldTypeAt
formFieldTypeAt(x: number, y: number): numberNon-mutating hit-test — safe on hover, unlike FormTap. -1 when there is no field.
formFocused
get formFocused(): booleanformInsertText
formInsertText(text: string): voidformKey
formKey(code: number): voidRaw key into the focused field. Backspace is 8, as the header specifies.
formSelectOption
formSelectOption(x: number, y: number, index: number): booleanformsInteractive
get formsInteractive(): booleanglyphCount
get glyphCount(): numbergroupCount
get groupCount(): numberHow many layers are in the current group (1 for a single selection, 0 for none).
hasForm
get hasForm(): booleanDoes this document have an AcroForm at all?
heapBytes
get heapBytes(): numberSize of the wasm heap in bytes.
highlightQuads
highlightQuads(x0: number, y0: number, x1: number, y1: number, multiLine?: boolean): number[][]The live markup QUADS for a swept range — the same geometry HighlightCommit will apply, so a preview drawn from these is WYSIWYG.
insertImage
insertImage(img: ImageData, at: { x: number; y: number; }, size: { w: number; h: number; }, kind?: 0 | 1 | 2 | 3 | 4, note?: string): booleanPlace an RGBA bitmap as a layer. img_kind tags the subtype the engine stores with it: 0 photo, 1 note, 2 signature, 3 drawing, 4 sound glyph — so a note stays re-editable as a note, a signature is recognisable on reopen, and a speaker glyph offers playback.
insertImagePageSpace
insertImagePageSpace(img: ImageData, box: { left: number; bottom: number; right: number; top: number; }, kind?: 0 | 1 | 2 | 3 | 4, note?: string): booleanPlace an image by PAGE-space rect (left, bottom, right, top in points, y-UP) rather than viewport px. The y axis is flipped relative to insertImage — page space is PDF space.
insertLinkText
insertLinkText(uri: string, at: { x: number; y: number; }): booleanDrop a NEW text layer reading uri at at (canvas px) and attach uri to it as a link — the Link tool with nothing selected. iOS's insertLinkTextLayer: the prompt already has the URL, so there is nothing to type; the text is seeded through the same edit session the keyboard would use, committed, and the link attached over the layer's bounds.
insertPage
insertPage(pageIndex?: number, wPt?: number, hPt?: number): booleanInsert a blank page AT pageIndex — the new page takes that index and everything from there on shifts up one — sized in POINTS. Pass 0 for either dimension to get the CURRENT page's size, which is what both defaults now do.
insertTextBox
insertTextBox(at: { x: number; y: number; }): booleanPlace a text box at at (canvas px) and OPEN IT FOR TYPING, with the placeholder selected so the first keystroke replaces it. This is the whole "add text" gesture, and it is public because the shell needs it WITHOUT a click: arming Text inserts the box straight away rather than loading the next click (see armTool). The click path calls the same method, so both routes place identically.
invalidate
invalidate(): voidAsk for a frame.
isEditing
get isEditing(): booleanisPointInSelection
isPointInSelection(xCss: number, yCss: number): booleanisPointOverText
isPointOverText(x: number, y: number): booleanIs a point on — or within snapping range of — selectable text? Probed with a 4px span, exactly as the iOS shell does, so a markup drag that starts on empty page PANS instead of marking nothing.
knobRect
knobRect(): { x: number; y: number; w: number; h: number; } | nullThe rotate knob's rect in canvas pixels, or null. Pure read.
layerBoxAt
layerBoxAt(x: number, y: number): HoverBox | nullThe box of whatever a press at this point would select — or null.
layers
layers(): { index: number; kind: LayerKind; objectCount: number; x: number; y: number; w: number; h: number; }[]Every layer on the page: kind and page-space box. Enough to build a layer list.
layerText
layerText(): stringThe SELECTED LAYER's whole text, and a replacement for it (same font, size and position). These live on the document handle and are NOT the edit session's range — to replace a range, set the range and type over it.
license
get license(): LicenseInfoThe license verdict this editor is running under.
linkUriAt
linkUriAt(x: number, y: number): stringThe link URI under a point, or '' — for a hover tooltip or a click-through.
markupColor
get markupColor(): numberThe colour the armed markup tool will commit with — the preview must paint in it.
markupOpacity
get markupOpacity(): numbermaxZoom
get maxZoom(): numberminZoom
get minZoom(): numberThe zoom range in force, after the engine's clamping — not the options as written. A host greying out its zoom buttons reads these, and an option the engine corrected (minZoom: 2, maxZoom: 9) would otherwise leave a button lit that can no longer move anything.
moveCaret
moveCaret(x: number, y: number): booleanmoveField
moveField(dx: number, dy: number): booleanmovePage
movePage(from: number, to: number): booleannearestOffset
nearestOffset(x: number, y: number): numberThe offset nearest a point — for click-to-place and drag-to-select.
noteAnnots
noteAnnots(): { x: number; y: number; w: number; h: number; color: number; text: string; }[]The note ANNOTATIONS on the active page: the ones stored in the PDF. A shell that wants every note has to read both, and they are disjoint: after a save-and-reopen the image layer is gone and the annotation is all that is left.
noteCount
get noteCount(): numbernudge
nudge(dx: number, dy: number): voidNudge the selection by whole canvas pixels — one keypress, one undo step.
open
open(pdf: Uint8Array, pageIndex?: number, password?: string): voidOpen a PDF. The bytes are copied into wasm memory and owned by the editor.
outlineBoxes
outlineBoxes(): OutlineBox[]outlineBoxToView
outlineBoxToView(box: OutlineBox): { x: number; y: number; w: number; h: number; } | nullAn OutlineBox (from outlineBoxes / fieldOutlineBoxes) to canvas pixels, doing the y-flip those boxes need: they are centre-origin and y-DOWN from the page top, while pageToView wants a bottom-left corner y-UP from the page bottom. Null on the same pages pageToView gives up on. The angle is not applied — a rotated box is not an axis-aligned rectangle; read it off the box.
overlayResReady
overlayResReady(w: number, h: number): booleanpageContentClass
get pageContentClass(): number0 = the page is a scan with no selectable text.
pageCount
get pageCount(): numberpageRect
pageRect(): { x: number; y: number; w: number; h: number; } | nullpageSizePoints
pageSizePoints(index: number): { w: number; h: number; } | nullDisplayed size of a page in POINTS, post-rotation — so a /Rotate 90 page reports landscape.
pageToView
pageToView(x: number, y: number, w: number, h: number): { x: number; y: number; w: number; h: number; } | nullPage points (y-UP, as layers() reports them) to CANVAS PIXELS — the backing-store space the pointer pipeline and tapSelect use, NOT CSS pixels. (It said "CSS pixels" and that was wrong: the canvas is sized r.width * devicePixelRatio, so a caller who believed the docstring and multiplied by devicePixelRatio probed at twice the offset on every Retina display. Divide by devicePixelRatio to position a DOM element, as drawPlacement does.)
panBy
panBy(dx: number, dy: number): voidPan the canvas by a delta in canvas px, self-clamping at the page's edges.
panY
get panY(): numberVertical pan of a tall page, and how far it can travel.
pasteAt
pasteAt(x: number, y: number): booleanplacementPoints
get placementPoints(): { x0: number; y0: number; x1: number; y1: number; } | nullThe placement drag AS IT WAS MADE — where it started and where the pointer is now — rather than the normalised box placementRect reports.
placementRect
get placementRect(): { x: number; y: number; w: number; h: number; } | nullThe rectangle a place-tool drag has swept so far, in canvas px — for the shell's preview.
prepareOverlayRes
prepareOverlayRes(w: number, h: number): voidPre-render the overlay at a target resolution, and ask whether it is ready.
probe
probe(pdf: Uint8Array, password?: string): 'ok' | OpenFailureClassify a PDF without opening it — encrypted, damaged, or fine.
radioGroups
radioGroups(): string[]readOnly
get readOnly(): booleanreanchorTop
reanchorTop(): voidRe-anchor the view to the page top (after a rotation or a page change).
recolorHighlights
recolorHighlights(rgba: number): voidRecolour the markup attached to the selected TEXT layer (not the text itself).
redo
redo(): voidredoPage
get redoPage(): numberrenderPageThumbnail
renderPageThumbnail(pageIndex: number, w: number, h: number): ImageData | nullRasterise one page for a thumbnail. CPU-only and safe off the render path — this is the same call the mobile shells use to fill their page rails.
replaceRange
replaceRange(a: number, b: number, text: string): numberReplace [a, b) with text; returns the caret offset afterwards.
resetForm
resetForm(): booleanClear every field back to its default — one undo step.
resizeField
resizeField(which: number, dx: number, dy: number): booleanOne-shot resize by a handle delta.
revealSearchHit
revealSearchHit(margin?: number): voidScroll the current match into view on the active page — the web half of iOS's ensureSearchHitVisible. A hit below the fold of a zoomed page is as invisible as one on another page. CanvasPanBy self-clamps, so a page that already fits simply does not move.
rotatePage
rotatePage(index: number, quarterCw?: number): booleanquarterCw: 1 = 90° clockwise, -1 = anticlockwise, 2 = 180°.
rotateSelectionBy
rotateSelectionBy(deg: number): voidTurn the selection by deg (clockwise, screen degrees) about its centre — ONE undo step, the way nudge moves it. A crop or a replace re-inserts an image upright; this puts a rotated one back at the angle it had. (Within 5° of a multiple of 45° the engine's angle snap takes it the rest of the way.)
save
save(): Uint8Array<ArrayBuffer> | nullscaleField
scaleField(factor: number): booleanThe one-shot convenience: the whole drag lifecycle in one call, one undo step.
searchClose
searchClose(): voidsearchCurrentRect
searchCurrentRect(): { x: number; y: number; w: number; h: number; } | nullThe current search hit's rect, so the shell can scroll it into view.
searchInfo
searchInfo(): { current: number; total: number; done: boolean; } | nullsearchNav
searchNav(dir: number): numberStep to the next (dir 1) or previous (dir -1) match and GO TO ITS PAGE.
searchStart
searchStart(query: string, matchCase?: boolean): booleanselectedFieldKind
get selectedFieldKind(): numberselectedFieldRect
selectedFieldRect(): { x0: number; y0: number; x1: number; y1: number; } | nullselectedImage
selectedImage(wantOriginal?: boolean): ImageData | nullThe selected image's pixels as straight-alpha RGBA. wantOriginal returns the stashed pre-crop copy, which is what makes cropping non-destructive: stash once, then every later crop starts from the full image rather than from the last crop.
selectedLink
selectedLink(): stringThe URI on the SELECTED layer. This is the read-back for setLink; LinkUriAt is a different question — it reads link annotations the DOCUMENT ARRIVED WITH, and an authored link only becomes one of those on Save.
selectedNoteText
selectedNoteText(): stringThe selected note's stored text, so a note stays re-editable rather than being a picture.
selectedProps
selectedProps(): SelectedProps | nullRead the selection's properties back from the engine. This is what makes the contextual toolbar real rather than a guess: the shell does not track what kind of layer is selected, it asks.
selectedRadioGroup
selectedRadioGroup(): stringselectedSound
selectedSound(): Uint8Array<ArrayBuffer> | nullThe selected sound's bytes, or null.
selectFieldAt
selectFieldAt(x: number, y: number): numberSelect the widget at a point. Returns its FPDF_FORMFIELD_* kind, or -1.
selectionBox
selectionBox(): { cx: number; cy: number; w: number; h: number; angle: number; } | nullThe selection's oriented box in canvas pixels, or null. Pure read.
selectionRange
get selectionRange(): [number, number] | nullThe live range as [a, b), or null when the selection is a plain caret.
selectionViewRect
selectionViewRect(): { x: number; y: number; w: number; h: number; } | nullThe selection's AXIS-ALIGNED screen rect, which is what a menu anchors to.
setActivePage
setActivePage(index: number): booleansetBottomInset
setBottomInset(px: number): voidThe height (px) a FLOATING tool picker covers at the bottom of the canvas. While something is being drawn near the page's foot, the page lifts to clear it, the way it lifts for a keyboard; 0 clears it. This does not re-centre the page — setInsets does that for chrome that overlays the canvas.
setCanvasColor
setCanvasColor(css: string): voidSet the surround colour behind the page. The engine paints it, not CSS, so a theme change has to reach it — otherwise the page floats on last theme's ground. Accepts anything getComputedStyle returns: rgb(r, g, b) or #rrggbb.
setCaretOffset
setCaretOffset(off: number): voidsetChromeZoom
setChromeZoom(z: number): voidKeeps selection chrome a fixed SCREEN size as the canvas zooms.
setCJKFallbackFont
setCJKFallbackFont(bytes: Uint8Array): voidA pan-CJK fallback face for RENDERING non-embedded CJK text the platform cannot cover. PROCESS-GLOBAL — it takes no editor handle — so register it once at startup, before opening anything. Pass an empty array to clear it.
setClipboardData
setClipboardData(bytes: Uint8Array): booleansetCornerHandlesOnly
setCornerHandlesOnly(on: boolean): voidRestrict a selection to CORNER handles only (as text already is). Holds across open().
setDocumentViewport
setDocumentViewport(w: number, h: number): voidThe DOCUMENT-level viewport, in device px.
setDrawPageShadow
setDrawPageShadow(on: boolean): voidThe drop shadow under the page. Holds across open().
setFaux
setFaux(bold: boolean, italic: boolean): voidFAUX bold/italic — synthesised on the CURRENT face, so an embedded subset keeps its outlines.
setFieldBorderWidth
setFieldBorderWidth(w: number): booleansetFieldColor
setFieldColor(which: 0 | 1 | 2, rgba: number): booleanwhich: 0 background, 1 border, 2 text — the engine's convention. Alpha 0 means "none" (0 and 1 only).
setFieldOptions
setFieldOptions(options: string[]): booleansetFillColor
setFillColor(rgba: number): voidsetFloatingCursor
setFloatingCursor(on: boolean, x?: number, y?: number, h?: number): voidThe free-flying "floating cursor" — a caret bar that follows a pointer without snapping to glyphs. Purely visual; the real caret is committed once, on release.
setFont
setFont(family: 0 | 1 | 2, bold: boolean, italic: boolean): voidsetFontData
setFontData(bytes: Uint8Array, postScriptName: string): booleanRebuild the selected text in an ARBITRARY font from its TTF/OTF bytes.
setFontFamily
setFontFamily(family: 0 | 1 | 2): voidA standard family (0 Helvetica, 1 Times, 2 Courier) for every selected run, each keeping ITS OWN bold and italic — unlike setFont, which gives the whole selection one style, so a group of a bold heading and plain text came out all one weight. One undo step.
setFontProvider
setFontProvider(provide: ((codepoint: number, style: number) => Uint8Array | null) | null): voidSupply fallback faces on demand: the engine calls back with a codepoint and a style (bit0 bold, bit1 italic) and the host returns a face that matches, so typed fallback text keeps the surrounding weight instead of flattening to regular.
setFontSize
setFontSize(pt: number): voidsetFormsInteractive
setFormsInteractive(on: boolean): voidLet a READ-ONLY document's form fields still be focused and filled.
setGpuCacheBudget
setGpuCacheBudget(bytes: number): voidCap the renderer's GPU resource cache, in bytes. A plain number is fine — it's converted for the engine here, so callers never deal with BigInt.
setInkStyle
setInkStyle(rgba: number, width: number): voidColour and width of the freehand stroke, 0xRRGGBBAA and canvas px.
setInsets
setInsets(top: number, bottom: number): voidChrome insets. The page centres between them, so a toolbar that OVERLAYS the canvas tells the engine its height here rather than shrinking the viewport — that is what lets the page reveal itself behind the chrome instead of jumping.
setKeyboardInset
setKeyboardInset(px: number): voidsetLayerText
setLayerText(text: string): booleansetLiftFrozen
setLiftFrozen(on: boolean): voidsetLink
setLink(uri: string): booleanAttach a URI to the current selection (the Link tool). An EMPTY uri removes the link.
setLoupe
setLoupe(on: boolean, x?: number, y?: number): voidsetLoupeHighlight
setLoupeHighlight(on: boolean, at: { x: number; y: number; }, from: { x: number; y: number; }, to: { x: number; y: number; }, rgba: number, markupKind: number): voidThe loupe with a live markup preview inside it, and its sampled row LOCKED to the start line — so a drag along a paragraph cannot let the magnifier drift onto the line above or below while you are aiming at a word.
setMarkupColor
setMarkupColor(rgba: number): voidColour used by the markup tools, 0xRRGGBBAA.
setMarkupOpacity
setMarkupOpacity(a01: number): voidOpacity alone, 0..1. The RGB is kept, exactly as the mobile shells store the two.
setNewTextFont
setNewTextFont(bytes: Uint8Array | null, postScriptName?: string): voidA font for NEW text boxes (TTF/OTF bytes): a placed box is set in it, while its size and colour still follow the text around it. postScriptName is the face's name — the same key {@link setFontData} caches by, so picking that font later embeds one copy. Loaded when the first box is placed; a file that won't load is dropped and new text uses the standard face. null clears it. Holds across open().
setNewTextPlaceholder
setNewTextPlaceholder(text: string): voidThe word a NEW text box starts with — "Text" in your app's language. It is selected when the box is placed, so the user types over it. Used when the box's font can draw every letter of it, else "Text". '' restores "Text". Holds across open().
setNoteColors
setNoteColors(card: number, text: number): voidsetOpacity
setOpacity(a01: number): voidsetPreviewPan
setPreviewPan(dx: number, dy: number): booleansetPreviewZoom
setPreviewZoom(scaleFromStart: number, ax: number, ay: number): voidsetRadioGroup
setRadioGroup(name: string): booleansetReadOnly
setReadOnly(on: boolean): voidViewer mode: render, zoom, page and search still work; the document cannot be edited.
setRotateIcon
setRotateIcon(icon: ImageData | null): booleanThe glyph inside the rotation knob, drawn as a template — its alpha filled with the selection colour — and fitted into the knob. At most 512×512. null restores the built-in arrow. Returns false (and changes nothing) for a bad size. Holds across open().
setScrollQuality
setScrollQuality(level: number): voidLower-quality raster while a scroll is in flight; restore on settle.
setSearchHighlightColors
setSearchHighlightColors(colors: { match?: string; current?: string; }): voidThe search highlights' colours: every match, and the current one. CSS colours; only the colour is used — the translucency is the engine's, so the text under a highlight always reads. Leave one out for the default (yellow / orange). Holds across open().
setSelectionRange
setSelectionRange(a: number, b: number): voidSelect a character range in the live session; offsets are UTF-16 code units. b <= a clears it back to a plain caret. The engine only DRAWS this — see replaceRange for who acts on it.
setSelectionStyle
setSelectionStyle(style: PDFSelectionStyle): voidThe selection's look: the box, its handles and rotation knob, the text caret and selection band, and the page-alignment guide. Every field is optional and falls back to the shipped look; sizes are clamped the way the engine clamps them (handleScale 0.75–1.5, borderWidth 1–3 CSS px). Colours are drawn opaque. A mouse's reach for the handles follows handleScale. Holds across open().
setShapeColors
setShapeColors(fill: number, stroke: number): voidsetShapeStrokeWidth
setShapeStrokeWidth(px: number): voidStroke width for the NEXT shape, in CSS px. The shapes were inserted with a hardcoded 2 * devicePixelRatio no matter what the shell's draw controls said, so a Draw toolbar reading "12" produced a 2px rectangle — the control described something the insert never read. (A SELECTED shape's width is setStrokeWidth; this one is the tool's own default.)
setShowAllLayerOutlines
setShowAllLayerOutlines(on: boolean): voidDashed hint boxes around every selectable layer. Holds across open().
setSound
setSound(data: Uint8Array, name: string): booleanAttach sound bytes to the current selection (the Sound tool).
setStrikethrough
setStrikethrough(on: boolean): voidsetStrokeColor
setStrokeColor(rgba: number): voidsetStrokeWidth
setStrokeWidth(w: number): voidsetTextStyle
setTextStyle(bold: boolean | null, italic: boolean | null): voidThe B and I buttons: make EVERY selected run bold / italic, or not, whatever its face. One undo step. null leaves that style as each run has it — a press of I must not decide the bold of a group that is only partly bold.
setUnderline
setUnderline(on: boolean): voidsha256
sha256(data: Uint8Array): Uint8ArraySHA-256 of a buffer — needed to VERIFY a signature's ByteRange yourself.
shapeStrokeWidth
get shapeStrokeWidth(): numbersignatureCertLevel
signatureCertLevel(pdf: Uint8Array, index: number): number0 approval; 1/2/3 a DocMDP certification level. Editing breaks certification.
signatureCount
signatureCount(pdf: Uint8Array): numberHow many signatures a document already carries.
signatureData
signatureData(pdf: Uint8Array, index: number): { byteRange: [number, number, number, number]; cms: Uint8Array; } | nullA signature's /ByteRange and its raw CMS, for host-side verification.
signatureInfo
signatureInfo(pdf: Uint8Array, index: number): { subFilter: string; reason: string; time: string; coversWholeFile: boolean; } | nullsignPDF
signPDF(pdf: Uint8Array, sign: (digest: Uint8Array) => Uint8Array | null, opts?: { reason?: string; location?: string; name?: string; contact?: string; fieldName?: string; signingTime?: string; pageIndex?: number; rect?: { x: number; y: number; w: number; h: number; }; cmsCapacity?: number; }): { bytes: Uint8Array | null; code: number; }Sign a document. sign receives the SHA-256 digest and must return a detached PKCS#7/CMS (DER), or null to abort.
soundAnnots
soundAnnots(): { x: number; y: number; w: number; h: number; data: Uint8Array; }[]SDK-created sound attachments on the active page, with page-space bounds and copied audio.
soundCount
get soundCount(): numberstashImageOriginal
stashImageOriginal(img: ImageData): voidStash a pre-crop original so the next crop starts from the full image.
swipeBegin
swipeBegin(dir: 1 | -1): booleanswipeEnd
swipeEnd(commit: boolean): numberCommit (SetActivePage) or cancel. Returns the page now showing.
swipeMove
swipeMove(dxPx: number): voidswitchEditLine
switchEditLine(x: number, y: number): booleanMove the session to another LINE of the same paragraph without closing it.
tapSelect
tapSelect(x: number, y: number): booleanSelect whatever is at a point, exactly as a tap does.
toggleGroupAt
toggleGroupAt(x: number, y: number): numberAdd or remove the layer at a point from the multi-select group; returns the new member count.
tool
get tool(): Tool
set tool(t: Tool)The armed tool.
trimMemory
trimMemory(): voidRelease caches under memory pressure.
typeText
typeText(text: string): voidundo
undo(): voidUndo/redo the next step in the DOCUMENT's history, turning to the page that owns it if needed.
undoPage
get undoPage(): numberThe page owning the next undo (resp. redo) step, or -1. undoPage === activePage means it is local.
vScrollRange
get vScrollRange(): numberzoom
get zoom(): numberzoomBy
zoomBy(factor: number): voidZoom about the canvas centre, the way the toolbar's -/+ do.
Types
HoverBox
export interface HoverBox { cx: number; cy: number; w: number; h: number; angle: number; kind: LayerKind; fieldType?: number; }The box a hover outlines: centre-origin, in canvas CSS px, with the layer's rotation.
LayerKind
export type LayerKind = 'text' | 'image' | 'path'LicenseInfo
export interface LicenseInfo { status: LicenseStatus; licensed: boolean; reason: string; licensee: string; licenseId: string; plan: string; keyId: string; issued: string; expires: string; updatesUntil: string; platform: string; identity: string; web: string[]; ios: string[]; macos: string[]; android: string[]; sdkVersion: string; sdkReleaseDate: string; online: boolean; server: string; paymentDue: boolean; leaseExpires: number; message: string; }LicenseStatus
export type LicenseStatus = 'valid' | 'development' | 'unlicensed' | 'invalid' | 'expired' | 'wrongApp' | 'wrongPlatform' | 'versionNotCovered' | 'unknownSigningKey' | 'suspended' | 'verificationRequired'The license verdict for this page, as the engine decided it.
OpenFailure
export type OpenFailure = 'password' | 'corrupt' | 'unreadable'OutlineBox
export interface OutlineBox { cx: number; cy: number; w: number; h: number; angle: number; type: number; }A layer hint box exactly as the engine reports it: page points, centre-origin, with a rotation.
PDFEditorOptions
export interface PDFEditorOptions { wasmUrl?: string; licenseKey?: string; minZoom?: number; maxZoom?: number; canvasColor?: string; }PDFLicenseError
export declare class PDFLicenseError extends Error { readonly license: LicenseInfo; constructor(license: LicenseInfo); }Thrown by create / open when this site has no valid license key. license.reason says why.
PDFOpenError
export declare class PDFOpenError extends Error { readonly reason: OpenFailure; constructor(reason: OpenFailure); }PDFSelectionStyle
export interface PDFSelectionStyle { color?: string; handleFill?: string; handleShape?: 'rounded' | 'circle' | 'square'; handleScale?: number; borderWidth?: number; }The selection's look ({@link PDFEditor.setSelectionStyle}). Anything left out keeps the shipped look.
SelectedProps
export interface SelectedProps { kind: LayerKind; imageKind: 0 | 1 | 2 | 3 | 4; noteCardColor: number; noteTextColor: number; objectCount: number; fontSize: number; fontName: string; fontEmbedded: boolean; bold: boolean; italic: boolean; underline: boolean; strikethrough: boolean; opacity: number; fillColor: number; strokeColor: number; strokeWidth: number; isShape: boolean; shapeKind: number; hasHighlight: boolean; highlightColor: number; }Everything the property bar needs to decide what to OFFER is in here — a note's colours, whether a text layer carries markup, whether an image is a note or a signature — and reading half of it is how a shell ends up guessing the rest.
SelectionEvent
export interface SelectionEvent { selected: boolean; props?: SelectedProps; }Tool
export type Tool = 'select' | 'multi' | 'text' | 'image' | 'link' | 'note' | 'sound' | 'signature' | 'stamp' | 'highlight' | 'underline' | 'strikeout' | 'squiggly' | 'freehand' | 'rect' | 'ellipse' | 'line' | 'arrow' | 'page' | 'field-text' | 'field-check' | 'field-radio' | 'field-list' | 'field-combo' | 'fields'Every tool the SDK exposes. Which ones exist is not a UI decision — this list is the audited surface of the engine, and each entry below maps to an engine operation, not to a shell behaviour.
Digital signatures and the engine
createDigitalId
function createDigitalId(opts: { name: string; organization?: string; email?: string; persist?: boolean; }): Promise<DigitalId>Create a digital ID: an RSA-2048 key pair (private key non-extractable) and a self-signed X.509 v3 certificate valid for ten years.
detachedCms
function detachedCms(id: DigitalId, messageDigest: Uint8Array, signingTime: Date): Promise<Uint8Array>The detached PKCS#7/CMS over a SHA-256 message digest. The RSA signature covers the signed attributes encoded as a SET (tag 0x31) while they travel under an IMPLICIT [0] — swapping those is the classic reason a CMS verifies nowhere, so both encodings are built explicitly.
DigitalId
interface DigitalId { privateKey: CryptoKey; certificate: Uint8Array; issuer: Uint8Array; serial: Uint8Array; name: string; organization: string; email: string; createdAt: number; }A self-signed identity: the key stays in the browser, the certificate travels in every signature.
loadDigitalId
function loadDigitalId(): Promise<DigitalId | null>The ID saved in this browser, or null.
loadEngine
function loadEngine(wasmUrl?: string): Promise<PDFEditorModule>pdfDate
function pdfDate(d: Date): stringPDF date syntax for /M.
PDFEditorModule
interface PDFEditorModuleThe engine as loadEngine() resolves it — call that early to preload; PDFEditor.create loads it itself. Opaque: its members are internal.
SIGN_FAILURE
const SIGN_FAILURE: Record<number, string>SignaturePlacement
type SignaturePlacement = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'invisible'signatureRect
function signatureRect(placement: SignaturePlacement, pageW: number, pageH: number): { x: number; y: number; w: number; h: number; } | nullThe visible box in page points (y up from the bottom-left), or null for an invisible signature.
SignatureStatus
interface SignatureStatus { index: number; signer: string; time: string; reason: string; valid: boolean; coversWholeFile: boolean; certLevel: number; summary: string; problem?: string; }signDocument
function signDocument(editor: PDFEditor, pdf: Uint8Array, id: DigitalId, opts?: { reason?: string; location?: string; placement?: SignaturePlacement; pageIndex?: number; pageSize?: { w: number; h: number; }; signingTime?: Date; fieldName?: string; }): Promise<{ bytes: Uint8Array | null; code: number; }>Sign pdf with id. Two passes over identical options (see the file comment); the result is the input bytes verbatim plus an incremental update, so existing signatures survive and this can be used to counter-sign.
verifySignatures
function verifySignatures(editor: PDFEditor, pdf: Uint8Array): Promise<SignatureStatus[]>Verify every signature in pdf, in document order. Empty when the file carries none.
Document API
PDFDocumentEditor edits a PDF from code — headless, or the document an editor shows through editor.document. Its 59 members, then its 16 types.
PDFDocumentEditor.open
static open(pdf: Uint8Array, opts?: PDFDocumentOpenOptions): Promise<PDFDocumentEditor>Open a PDF headless (no canvas).
PDFDocumentEditor.close
close(): voidFree a headless document's engine. A live document belongs to its editor and ignores this.
PDFDocumentEditor.pageCount
get pageCount(): numberPDFDocumentEditor.pageSize
pageSize(page: number): { width: number; height: number; }The page's size in points (as displayed, i.e. after its rotation).
PDFDocumentEditor.save
save(): Uint8ArrayThe edited PDF.
PDFDocumentEditor.metadata
metadata(key: PDFMetadataKey): stringPDFDocumentEditor.setMetadata
setMetadata(key: PDFMetadataKey, value: string): voidWritten into the file save() produces.
PDFDocumentEditor.text
text(page: number): stringThe page's plain text.
PDFDocumentEditor.search
search(query: string, caseSensitive?: boolean): PDFSearchMatch[]Every match of query in the document.
PDFDocumentEditor.renderPage
renderPage(page: number, width: number, height: number): ImageData | nullThe page drawn into a width×height image (a thumbnail, a preview).
PDFDocumentEditor.canUndo
get canUndo(): booleanPDFDocumentEditor.canRedo
get canRedo(): booleanPDFDocumentEditor.undo
undo(): booleanUndo the last change, the user's or this API's. A layer that comes back gets a NEW id — read the layers again.
PDFDocumentEditor.redo
redo(): booleanPDFDocumentEditor.insertBlankPage
insertBlankPage(index: number, width?: number, height?: number): voidInsert a blank page at index (a zero size takes the neighbouring page's).
PDFDocumentEditor.deletePage
deletePage(index: number): voidPDFDocumentEditor.movePage
movePage(from: number, to: number): voidPDFDocumentEditor.duplicatePage
duplicatePage(index: number): voidPDFDocumentEditor.rotatePage
rotatePage(index: number, clockwise?: boolean): voidPDFDocumentEditor.importPages
importPages(pdf: Uint8Array, opts?: { password?: string; pages?: number[]; index?: number; }): voidCopy pages (all when omitted) of another PDF into this one at index (omitted = the end). This starts the undo history afresh, as a flatten does, and layer ids must be read again.
PDFDocumentEditor.extractPages
extractPages(pages: number[]): Uint8Arraypages of this document as a new PDF.
PDFDocumentEditor.layers
layers(page: number): PDFLayer[]Every layer of the page, in reading order (top to bottom, then left to right) for a page read the first time.
PDFDocumentEditor.textBlocks
textBlocks(page: number): PDFLayer[]PDFDocumentEditor.layer
layer(layer: PDFLayer): PDFLayerThe layer as it is now.
PDFDocumentEditor.image
image(layer: PDFLayer): ImageData | nullThe picture of an image layer, at its own pixel size.
PDFDocumentEditor.sound
sound(layer: PDFLayer): Uint8Array | nullThe audio of a sound layer.
PDFDocumentEditor.setText
setText(layer: PDFLayer, text: string, opts?: { shrinkToFit?: boolean; }): PDFTextResultReplace a text layer's text, keeping its font, size, colour and position. A paragraph re-wraps at its own width; a single line may grow to the page margin. shrinkToFit lowers the size (to half at most) until the text is no taller than before. Scripts the layer's font lacks need a font provider.
PDFDocumentEditor.setFontSize
setFontSize(layer: PDFLayer, points: number): voidPDFDocumentEditor.setFont
setFont(layer: PDFLayer, family: PDFFontFamily, opts?: { bold?: boolean; italic?: boolean; }): voidPDFDocumentEditor.setFontData
setFontData(layer: PDFLayer, data: Uint8Array, name: string): voidEmbed a font of your own (TTF/OTF bytes) and set the layer in it.
PDFDocumentEditor.setTextStyle
setTextStyle(layer: PDFLayer, opts: { bold?: boolean; italic?: boolean; }): voidBold / italic of the current family; omitted leaves that one as it is.
PDFDocumentEditor.setUnderline
setUnderline(layer: PDFLayer, on: boolean): voidPDFDocumentEditor.setStrikethrough
setStrikethrough(layer: PDFLayer, on: boolean): voidPDFDocumentEditor.setFillColor
setFillColor(layer: PDFLayer, rgba: number): voidText colour, or a shape's fill (0xRRGGBBAA).
PDFDocumentEditor.setStrokeColor
setStrokeColor(layer: PDFLayer, rgba: number): voidPDFDocumentEditor.setStrokeWidth
setStrokeWidth(layer: PDFLayer, points: number): voidPDFDocumentEditor.setOpacity
setOpacity(layer: PDFLayer, opacity: number): voidPDFDocumentEditor.setFrame
setFrame(layer: PDFLayer, f: PDFRect): voidMove and resize (text scales uniformly).
PDFDocumentEditor.setRotation
setRotation(layer: PDFLayer, degrees: number): voidDegrees, clockwise as seen.
PDFDocumentEditor.setZOrder
setZOrder(layer: PDFLayer, order: PDFZOrder): voidPDFDocumentEditor.setLink
setLink(layer: PDFLayer, url: string | null): voidnull removes the link.
PDFDocumentEditor.setSound
setSound(layer: PDFLayer, audio: Uint8Array, name: string): voidPDFDocumentEditor.replaceImage
replaceImage(layer: PDFLayer, image: ImageData): voidSwap an image layer's picture, keeping its frame and kind.
PDFDocumentEditor.setMarkup
setMarkup(layer: PDFLayer, kind: PDFMarkupKind, rgba: number): voidMark a whole text layer up.
PDFDocumentEditor.removeMarkup
removeMarkup(layer: PDFLayer): voidRemove a text layer's highlight / strikeout / squiggly.
PDFDocumentEditor.delete
delete(layer: PDFLayer): voidPDFDocumentEditor.duplicate
duplicate(layer: PDFLayer, dx?: number, dy?: number): PDFLayerA copy offset by (dx, dy) points.
PDFDocumentEditor.copy
copy(layer: PDFLayer, toPage: number, x: number, y: number): PDFLayerA copy on another page, its top-left at (x, y) there.
PDFDocumentEditor.addText
addText(text: string, page: number, x: number, y: number, opts?: { fontSize?: number; color?: number; family?: PDFFontFamily; }): PDFLayerA text layer with its top-left at (x, y).
PDFDocumentEditor.addImage
addImage(image: ImageData, page: number, frame: PDFRect, opts?: { kind?: PDFImageKind; note?: string; }): PDFLayerAn image layer filling frame. A signature, a hand drawing or a stamp is an image of that kind.
PDFDocumentEditor.addShape
addShape(shape: PDFShape, page: number, from: { x: number; y: number; }, to: { x: number; y: number; }, opts?: { fill?: number; stroke?: number; strokeWidth?: number; }): PDFLayerA rectangle or ellipse filling the rect from start to end, or a line / arrow from start to end.
PDFDocumentEditor.markupText
markupText(page: number, from: { x: number; y: number; }, to: { x: number; y: number; }, opts?: { kind?: PDFMarkupKind; color?: number; }): voidMark up the text between two points of the page, as a drag with the tool would.
PDFDocumentEditor.formFields
formFields(): PDFFormField[]PDFDocumentEditor.setFormValue
setFormValue(field: string, value: string): voidFill a field: its text, an option's label, "true"/"false" for a check box, or the export value of the radio button to turn on.
PDFDocumentEditor.fillForm
fillForm(values: Record<string, string>): voidFill several fields at once.
PDFDocumentEditor.addFormField
addFormField(kind: PDFNewFieldKind, page: number, frame: PDFRect, opts?: { name?: string; options?: string[]; }): stringA new field; returns its name (name, or one the editor made up). Radios that share a name are one set.
PDFDocumentEditor.deleteFormField
deleteFormField(name: string): voidRemove every widget called name (a whole radio set).
PDFDocumentEditor.resetForm
resetForm(): voidPDFDocumentEditor.flattenForm
flattenForm(): voidBake the fields into the pages (their values stay, they stop being editable).
PDFDocumentError
class PDFDocumentError extends Error { readonly code: 'cannotOpen' | 'notFound' | 'unsupportedGlyphs' | 'failed'; constructor( code: 'cannotOpen' | 'notFound' | 'unsupportedGlyphs' | 'failed', message?: string); }Why a document call failed.
PDFDocumentOpenOptions
interface PDFDocumentOpenOptions { password?: string; wasmUrl?: string; fontProvider?: (codepoint: number, style: number) => Uint8Array | null; }PDFFontFamily
type PDFFontFamily = 'sans' | 'serif' | 'mono'The built-in families every PDF reader has.
PDFFormField
interface PDFFormField { name: string; kind: PDFFormFieldType; page: number; frame: PDFRect; value: string; checked?: boolean; exportValue?: string; options: string[]; readOnly: boolean; }PDFFormFieldType
type PDFFormFieldType = 'text' | 'checkbox' | 'radio' | 'combobox' | 'listbox' | 'button' | 'signature' | 'unknown'PDFImageKind
type PDFImageKind = 'photo' | 'note' | 'signature' | 'drawing'What an image layer is to the editor: a signature, a hand drawing and a stamp are images it knows by kind.
PDFLayer
interface PDFLayer { page: number; id: number; kind: PDFLayerKind; frame: PDFRect; rotation: number; opacity: number; zIndex: number; link?: string; text?: string; fontName?: string; fontSize?: number; bold: boolean; italic: boolean; underline: boolean; strikethrough: boolean; fontEmbedded: boolean; symbolic: boolean; textColor?: number; highlightColor?: number; pixelWidth?: number; pixelHeight?: number; note?: string; noteColor?: number; noteTextColor?: number; shape?: PDFShape; fillColor?: number; strokeColor?: number; strokeWidth?: number; }One layer of a page, as data. Read again after a change — a layer's properties are a snapshot.
PDFLayerKind
type PDFLayerKind = 'text' | 'image' | 'note' | 'signature' | 'drawing' | 'sound' | 'shape' | 'vector'PDFMarkupKind
type PDFMarkupKind = 'highlight' | 'strikeout' | 'squiggly'PDFMetadataKey
type PDFMetadataKey = 'Title' | 'Author' | 'Subject' | 'Keywords' | 'Creator' | 'Producer'PDFNewFieldKind
type PDFNewFieldKind = 'text' | 'checkbox' | 'radio' | 'listBox' | 'dropdown'PDFRect
interface PDFRect { x: number; y: number; width: number; height: number; }A rectangle in page points, top-left origin.
PDFSearchMatch
interface PDFSearchMatch { page: number; rects: PDFRect[]; }PDFShape
type PDFShape = 'rectangle' | 'ellipse' | 'line' | 'arrow'PDFTextResult
type PDFTextResult = 'replaced' | 'overflow'How a text replacement went: it fits where the old text was, or it is taller (may run into what is below).
PDFZOrder
type PDFZOrder = 'toBack' | 'backward' | 'forward' | 'toFront'Web
The engine runs in the page as WebAssembly and draws into a <canvas> you provide. PDFEditor is the whole API: open bytes, let the user edit, take bytes back. Nothing is uploaded — the document never leaves the tab.
iOS, iPadOS & Mac Catalyst
A complete editor UI you present with one view: PDFEditorView in SwiftUI or PDFEditorViewController in UIKit. Give it a PDF file, get the edited bytes back.