Release v2.14.3
-
#638 by @bobsingor – Fix two bugs that caused polygon (and square/circle) annotations created via the
createAnnotationAPI withstrokeStyle: PdfAnnotationBorderStyle.CLOUDYto be saved as a half-built stub missing/C,/IC,/CA,/F,/BE,/RD, and/AP:- Normalise
PdfAnnotationBorderStyle.CLOUDYtoSOLIDinsidesetBorderStylebefore calling PDFium'sEPDFAnnot_SetBorderStyle. Cloudy is not a/BS/Svalue — it is conveyed via the separate/BE(border effect) dict, whichsetBorderEffectalready writes. PDFium previously rejected the call and aborted the rest ofaddPolyContent/addShapeContent, so the cloudy effect, colors, opacity, flags, and appearance stream were never written. - Fix the rollback path in
createPageAnnotationso failed content-add calls actually remove the partially-built annotation. The previous code calledFPDFPage_RemoveAnnot(pagePtr, annotationPtr), but PDFium's C signature isFPDFPage_RemoveAnnot(FPDF_PAGE, int index)— the annotation pointer was interpreted as an out-of-range index and silently no-op'd, leaving the stub annotation in the page. It now usesremoveAnnotationByName(viaEPDFPage_RemoveAnnotByName) and closes the annotation handle.
The
PdfAnnotationBorderStyle.CLOUDYenum value is now treated as a deprecated alias forSOLID + cloudyBorderIntensityand is slated for removal in the next major release. - Normalise
-
#641 by @bobsingor – Populate
PdfPageObject.objectNumberfrom PDFium'sEPDFDoc_GetPageObjectNumberByIndexinopenDocumentBufferandimportPages, so pages now expose their PDF indirect-object number alongside their index, size, and rotation. -
#642 by @bobsingor – Preserve custom annotation
/NMvalues instead of rewriting them to a UUID v4.The engine previously overwrote any
/NM(annotation name) that wasn't a UUID v4 — both when creating new annotations (rewriting the caller'sannotation.id) and when reading existing ones (mutating the on-disk value as a side effect of opening a PDF). This broke any consumer using a custom identity scheme (e.g. ULIDs,firm-2024-001, etc.).The engine now only generates a UUID v4 when
/NMis empty or missing; any non-empty value is kept as-is. PDFium'sEPDFPage_GetAnnotByNamelookup only needs a unique string, so no functional behaviour changes for callers that don't supply a custom id.
- #641 by @bobsingor – Add
objectNumber: numbertoPdfPageObject, populated by the engine fromEPDFDoc_GetPageObjectNumberByIndex. Lets consumers correlate pages with their PDF indirect-object numbers (e.g. for linking, debugging, or round-tripping raw object references).PdfPageObjectis engine-owned — only the engine constructs it — so this is additive for all practical consumers.
-
#638 by @bobsingor – Fix callout FreeText annotations rendering with a black background when the fill color is transparent.
In
GenerateFreeTextAP's callout branch, the text-box rectangle was painted unconditionally with operatorB(fill + stroke). When/Cwas absent, no fill colour was emitted, soBfell back to PDF's default black fill. Now the fill defaults to transparent viaGetColorStringWithDefaultand the paint operator is picked dynamically withGetPaintOperatorString, mirroringGenerateCircleAP/GenerateSquareAP. -
#640 by @bobsingor – Fix page layout shifting after editing PDFs whose
/Contentsis a split-stream array (e.g. after redaction).PDF renders
/Contentsas one continuous program, so graphics state set in one stream carries into the next. The previous behaviour rewrote only the dirty streams while keeping the original split boundaries, which could corrupt the graphics-state handoff between streams and shift the visible layout.CPDF_PageContentGenerator::GenerateContentnow collapses all active page objects into a single canonical content stream when the page has been edited, viaGenerateCanonicalPageStream+CPDF_PageContentManager::ReplaceWithSingleStream. Form XObjects keep their existing single-stream behaviour.
-
#638 by @bobsingor – Re-export the annotation API surface from
@embedpdf/modelsthrough the snippet bundle so consumers can use named enums and typed annotation shapes instead of hardcoding numeric subtype/border-style values.Newly exported from
@embedpdf/snippet:- Enums:
PdfAnnotationBorderStyle,PdfAnnotationLineEnding,PdfAnnotationFlags,PdfAnnotationName,PdfAnnotationIcon,PdfAnnotationState,PdfAnnotationStateModel,PdfAnnotationReplyType,PdfAnnotationObjectStatus,PdfBlendMode,PdfStampFit,AppearanceMode. - Annotation flag helpers:
PdfAnnotationFlagName,flagsToNames,namesToFlags. - Annotation object types:
PdfAnnotationObjectBase,PdfAnnotationObject,PdfSupportedAnnoObject,PdfUnsupportedAnnoObject,PdfTextAnnoObject,PdfLinkAnnoObject,PdfFreeTextAnnoObject,PdfLineAnnoObject,PdfSquareAnnoObject,PdfCircleAnnoObject,PdfPolygonAnnoObject,PdfPolylineAnnoObject,PdfHighlightAnnoObject,PdfUnderlineAnnoObject,PdfSquigglyAnnoObject,PdfStrikeOutAnnoObject,PdfCaretAnnoObject,PdfInkAnnoObject,PdfInkListObject,PdfPopupAnnoObject,PdfFileAttachmentAnnoObject,PdfWidgetAnnoObject,PdfRedactAnnoObject,PdfRectDifferences,LinePoints,LineEndings,PdfAnnotationOf. - Create-context types:
AnnotationCreateContext,AnnotationContextMap. - Geometry / color:
Position,Size,Rect,WebColor.
PdfAnnotationSubtypeandPdfStampAnnoObjectwere already exported and continue to work unchanged. - Enums:
-
#638 by @bobsingor – Add Brazilian Portuguese (
pt-BR) as a built-in locale of the snippet viewer.- New
brazilianPortugueseTranslationsexport from@embedpdf/snippet, covering the full translation schema so users see localised strings everywhere (search panel, password prompt, document-error dialog, outline, comments, blend-mode picker, link dialog, full protect/security flows, signature flow, etc.) — no English fallback noise. - Registered in the default
i18n.localesarray alongside the existing nine locales, so the viewer's language picker now lists "Português (Brasil)" out of the box. - The wide-label responsive override that used to be German/Dutch-only now also applies to
pt-BR, because words like "Visualizar" (10) and "Formulário" (10) are as wide as German labels and would otherwise overflow the toolbar at themdbreakpoint. The override group id was renamed fromgermanic-languagestowide-label-languagesto reflect the broader scope; behaviour forde/nlis unchanged.
- New
Release v2.14.2
-
#607 by @bobsingor – Add
fontsconfiguration to the snippet viewer for controlling external webfont loading. Both defaults remain unchanged (Open Sans for the UI chrome, Caveat / Dancing Script / Great Vibes / Pacifico for the Create Signature "Type" tab), but integrators can now opt out cleanly for GDPR-sensitive, airgapped, or self-hosted deployments.fonts.ui: controls the snippet UI font.nullskips the<link>(falls back to the system font stack); an object withfamilyand/orstylesheetUrllets you change the viewer font family independently from the stylesheet source, with omittedstylesheetUrltreated as no managed<link>.fonts.signature: controls the signature "Type" tab fonts.nullskips the<link>and hides the "Type" tab; an object withstylesheetUrland/orfontslets you self-host the stylesheet and override the font list.
Both stylesheets are now registered at document scope with deduped
<link rel="stylesheet">elements so@font-faceworks consistently across browsers and typed signatures can render correctly to canvas. Existing matching stylesheet links are reused when possible. -
#607 by @bobsingor – Prevent the zoom percentage
%symbol in the custom zoom toolbar from wrapping to a new line when the toolbar is resized to a narrow width. The input and%are now rendered as a single non-wrapping flex group that clips overflow instead of breaking the layout.
Release v2.14.1
- #601 by @bobsingor – Add
PdfAnnotationFlags.LOCKED_CONTENTS(1 << 9) and map it to the'lockedContents'PdfAnnotationFlagName, extending flag parsing helpers (flagsToNames,namesToFlags) accordingly.
- #601 by @bobsingor – Add PDF
LOCKED_CONTENTSflag handling and granular lock helpers (hasNoViewFlag,hasHiddenFlag,hasReadOnlyFlag,hasLockedContentsFlag). ExposeisAnnotationInteractive,isAnnotationStructurallyLocked,isAnnotationContentLocked, andisAnnotationSelectableon the plugin API. Update annotation rendering across React/Preact, Svelte, and Vue to skipnoView/hiddenannotations and gate interactions using the new predicates. ThreadstructurallyLockedandcontentLockedthrough the selection menu context on all three stacks so custom menus can disable structural or content edits without re-reading flag arrays.
-
#601 by @bobsingor – Align annotation fill-mode toolbar commands with plugin-configured default lock state via
getDefaultAnnotationLock, and swap unlock vs form-only lock behavior so defaults match the intended modes. Re-exportLockModeTypefrom the snippet’s publicembedpdfentry for consumers. -
#598 by @ngivanyh – Add Traditional Chinese (
zh-TW) locale strings to the snippet viewer, register them in the default translation bundle, and exposezh-TWin the CJK language group of the UI schema so users can select 繁體中文 in the viewer.
Release v2.14.0
- #581 by @bobsingor – Support callout free text in the PDFium executor: read/write
/CL,/LE,/IT, stroke width and colors,/TextColor, and remap rectangle differences (/RD) between native PDFium order and the model shape.
- #581 by @bobsingor – Extend free text annotation typing for callouts: add
PdfAnnotationColorType.TextColorand optionalcalloutLine,lineEnding,strokeWidth, andstrokeColoronPdfFreeTextAnnoObject.
- #581 by @bobsingor – Expose EmbedPDF callout line helpers in the WASM bindings (
EPDFAnnot_GetCalloutLineCount,EPDFAnnot_GetCalloutLine,EPDFAnnot_SetCalloutLine) and refresh bundledpdfium.js/pdfium.cjs/pdfium.wasm.
- #581 by @bobsingor – Add callout free text (
FreeTextCallout): creation handler and preview data, vertex config and patch pipeline, defaultfreeTextCallouttool, and built-in renderers for React, Vue, and Svelte (including preview components and sharedcalloutVertexConfig).
- #581 by @bobsingor – Wire callout into the snippet viewer: callout icon,
annotation:add-calloutcommand, annotation toolbar and overflow menu entries, translations, and sidebar property schema forfreeTextCallout(including opaque stroke color control).
Release v2.13.0
- #579 by @bobsingor – Add the Signature plugin: reusable signature and initials entries, draw/type/upload pads, placement as ink or stamp annotations, and framework bindings for React, Vue, Preact, and Svelte.
- #579 by @bobsingor – Re-export patching utilities from
./patchingso dependent plugins (for example signature placement) can reuse the shared patch helpers.
- #579 by @bobsingor – Register the Signature plugin in the snippet viewer, add a create-signature modal and wire the signature sidebar to real entries, placement, and translations.
Release v2.12.1
- #571 by @bobsingor – Add
getAnnotations(options?)method to retrieve all tracked annotations, optionally filtered by page index. Available on bothAnnotationCapabilityandAnnotationScope.
- #571 by @bobsingor – Export missing annotation types from the snippet package:
AnnotationTransferItem,ExportAnnotationsOptions,GetAnnotationsOptions,TrackedAnnotation,AnnotationTool,PdfAnnotationSubtype, andPdfStampAnnoObject.
Release v2.12.0
- #569 by @bobsingor – Add symmetric annotation import/export API using a unified
AnnotationTransferItemtype.exportAnnotations()produces the same format thatimportAnnotations()consumes — zero remapping needed for round-tripping. Stamp appearances are automatically exported as PDF buffers inctx.data. On import, stamps can be created from PNG, JPEG, or PDF buffers viactx: { data: ArrayBuffer }— the engine auto-detects the format from magic bytes. Also addsdeleteAllAnnotations()convenience method.
Release v2.11.1
-
#557 by @jonashaag – Add BMP encoding support as an optional image format
BMP encoding bypasses canvas.toBlob() entirely by prepending a 66-byte header to the raw RGBA pixel data. This eliminates the dominant rendering bottleneck — in benchmarks, encoding dropped from ~76ms average (PNG via canvas.toBlob) to <1ms, reducing total tile render time by ~60%.
The BMP uses BI_BITFIELDS with channel masks matching PDFium's RGBA output byte order, so no per-pixel conversion is needed. Top-down row order avoids row flipping. The result is a valid BMP that all modern browsers decode natively in
<img>elements.Users who want to opt into the faster BMP path can set
defaultImageType: 'image/bmp'in the render plugin config, while PNG remains the default output format. -
#566 by @bobsingor – Fix custom stamp annotations with
imageSizeso predefined image stamps render correctly while preserving the original embedded bitmap quality.
-
#557 by @jonashaag – Add BMP encoding support as an optional image format
BMP encoding bypasses canvas.toBlob() entirely by prepending a 66-byte header to the raw RGBA pixel data. This eliminates the dominant rendering bottleneck — in benchmarks, encoding dropped from ~76ms average (PNG via canvas.toBlob) to <1ms, reducing total tile render time by ~60%.
The BMP uses BI_BITFIELDS with channel masks matching PDFium's RGBA output byte order, so no per-pixel conversion is needed. Top-down row order avoids row flipping. The result is a valid BMP that all modern browsers decode natively in
<img>elements.Users who want to opt into the faster BMP path can set
defaultImageType: 'image/bmp'in the render plugin config, while PNG remains the default output format.
- #566 by @bobsingor – Fix Vue and Svelte renderer registration typing so custom preview container styles build correctly.
-
#557 by @jonashaag – Add BMP encoding support as an optional image format
BMP encoding bypasses canvas.toBlob() entirely by prepending a 66-byte header to the raw RGBA pixel data. This eliminates the dominant rendering bottleneck — in benchmarks, encoding dropped from ~76ms average (PNG via canvas.toBlob) to <1ms, reducing total tile render time by ~60%.
The BMP uses BI_BITFIELDS with channel masks matching PDFium's RGBA output byte order, so no per-pixel conversion is needed. Top-down row order avoids row flipping. The result is a valid BMP that all modern browsers decode natively in
<img>elements.Users who want to opt into the faster BMP path can set
defaultImageType: 'image/bmp'in the render plugin config, while PNG remains the default output format.
- #566 by @bobsingor – Disable the snippet rubber stamp insert command when the active document does not allow annotation modifications.
Release v2.11.0
- #562 by @bobsingor – Implement new PDF manipulation and annotation appearance export methods:
createDocument,importPages,deletePage,exportAnnotationAppearanceAsPdf, andexportAnnotationsAppearanceAsPdf.
- #562 by @bobsingor – Add
PdfAnnotationNameenum (deprecatingPdfAnnotationIcon). ExtendPdfEngineandIPdfiumExecutorinterfaces with new document manipulation capabilities (createDocument,importPages,deletePage) and annotation appearance export methods.
- #562 by @bobsingor – Expose new PDFium functions for annotation appearance generation and export (
EPDFAnnot_ExportAppearanceAsDocument,EPDFAnnot_ExportMultipleAppearancesAsDocument,EPDFAnnot_SetAppearanceFromPage,EPDFAnnot_GetName,EPDFAnnot_SetName).
- #562 by @bobsingor – Add
ToolContextMapto support typed context injection for active tools. Introduce preview renderers and bounding-box components for annotations (CirclePreview,SquarePreview,InkPreview, etc.) to support drag-to-create or stamp hover previews.
- #562 by @bobsingor – Introduce
@embedpdf/plugin-stampfor managing reusable rubber-stamp libraries. Includes features for loading built-in/manifest stamps, creating custom stamps from annotations, and exporting custom stamp libraries.
- #562 by @bobsingor – Enhance sidebar API by allowing custom
propsto be passed viasetActiveSidebarandtoggleSidebar, enabling dynamic state injection into sidebar components.
- #562 by @bobsingor – Integrate
@embedpdf/plugin-stampwith the default viewer. Add the Rubber Stamp sidebar, Signature sidebar, and Insert tools to the default UI schema. Include standard stamp/insert translations.
Release v2.10.1
Automated release.