What's New in Document Solutions for PDF JS v9
v9.1 - May 5, 2026
Release of Document Solutions for PDF JavaScript (DsPdfJS)
We’re excited to introduce Document Solutions for PDF JavaScript (DsPdfJS), our new JavaScript PDF API library that brings core PDF document processing capabilities to JavaScript developers. With DsPdfJS, developers can create, load, edit, secure, optimize, and extract content from PDF documents using a JavaScript-first programming model, expanding the Document Solutions product line further into the JavaScript ecosystem.
This initial release focuses on the core PDF workflows developers need most, including:
- Document creation & editing
- Page operations: merge, split, insert, & remove
- Text extraction: search, replace, & delete
- Redaction
- Form handling: AcroForms
- Encryption
- Optimization
- Font support
- Raster image processing
- Annotations
As the main highlight of the v9.1 release, DsPdfJS opens the door for JavaScript developers to build modern PDF solutions for browser and server-side scenarios using the same Document Solutions approach to document APIs.
The below is just a quick overview of some of the features and functionality DsPdfJS has to offer. Discover more about all DsPdfJS has to offer by checking out our demos and documentation!
Create, Load, and Save PDFs
Document Solutions for PDF JavaScript (DsPdfJS) gives JavaScript developers a straightforward way to create, load, and save PDF documents in code. This is one of the core capabilities of the new product line, enabling applications to generate PDFs from scratch, open existing files for processing, and save results with configurable output options.
The main API centers on the PdfDocument class. Developers can create a new document with PdfDocument.create(), optionally supplying PdfDocumentOptions to control settings such as page size, PDF/A conformance, and font embedding behavior. Existing PDFs can be opened with PdfDocument.load(), and finished documents can be written out with savePdf(), including support for save options such as linearized output for faster web viewing. DsPdfJS also supports adding embedded files to a PDF using addEmbeddedFile(), making it possible to package related resources directly inside the document.
// Create a PDF
using rm = new ResourceManager();
const doc = PdfDocument.create(rm, {
defaultPageWidth: 595,
defaultPageHeight: 842,
conformanceLevel: PdfAConformanceLevel.PdfA1a,
fontEmbedMode: FontEmbedMode.EmbedFullFont
});
// Load a PDF
using rm = new ResourceManager();
const pdfDoc = PdfDocument.load(rm, await this.loadFileAsArray("Pdfs/ProcurementLetter.pdf"));
/* Loads a binary file from the specified URL */
async loadFileAsArray(url: string): Promise<Uint8Array> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Unable to load file: ${response.statusText}`);
}
const arrayBuffer = await response.arrayBuffer();
return new Uint8Array(arrayBuffer);
}
// Save a PDF
const res: Uint8Array = doc.savePdf({ saveMode: SaveMode.Linearized });
Merge, Split, Insert, and Remove Pages
DsPdfJS also provides the page-level editing features developers need for common PDF workflow automation, including splitting content, and inserting or removing pages. These capabilities are useful for assembling reports, extracting content into separate outputs, or restructuring existing PDF files entirely in JavaScript.
For merging, developers can use mergeWithDocument() to append pages from one PDF into another, with support for targeting a specific insertion point and page range. For inserting pages, DsPdfJS provides APIs such as newPageContext() for adding a new page and drawing on it immediately, along with page collection methods like insert() and insertNew() to place pages at a specific position in the document. Pages can be removed with remove() or removeAt(), making it easy to reorganize documents programmatically.
For split scenarios, DsPdfJS exposes split() and related SplitOptions support, which can be used to divide layout content across pages or carry overflow into a secondary layout. These options allow developers to control behaviors such as paragraph handling, widows and orphans, spacing, and the dimensions of the remaining layout area, giving them fine-grained control over how content is split when building multi-page PDF output.

const ds = window.DocSol;
async function createPdf() {
// Load an existing PDF:
const fn1 = "Wetlands.pdf";
const fn2 = "WetlandsReview.pdf";
const bytes1 = await loadFileAsArray(`pdfs/${fn1}`);
const bytes2 = await loadFileAsArray(`pdfs/${fn2}`);
const doc1 = ds.PdfDocument.load(bytes1);
const doc2 = ds.PdfDocument.load(bytes2);
// Merge doc2 into doc1:
doc1.mergeWithDocument(doc2);
return doc1;
}
Text Extraction: Search, Replace, and Delete
DsPdfJS includes built-in support for extracting and editing PDF text, making it useful for search-driven workflows, document cleanup, and content updates directly in JavaScript. Developers can retrieve page text, search for specific words or phrases, replace matched content, or remove text entirely without leaving the PDF processing pipeline.
For extraction and search, DsPdfJS provides getText() to retrieve all text from a page and FindTextParams to define search criteria such as the target text, case sensitivity, and whole-word matching. This makes it easier to build features such as indexing, validation, content inspection, or targeted text editing across PDF pages.
For editing, DsPdfJS supports both replaceText() and deleteText() on PdfPage. Developers can replace matched text with new content, optionally specifying a font and font size, or delete text using modes such as Standard or PreserveSpace depending on whether surrounding content should reflow. Together, these APIs give JavaScript developers a practical way to implement search, replace, and delete operations for real-world PDF modification scenarios such as updating names, dates, contact information, or removing unwanted text fragments.

const ds = window.DocSol;
async function createPdf()
{
const doc = ds.PdfDocument.load(await loadFileAsArray('PDF/LeaseAgreementDemo.pdf'))
// Replace:
// "Jane Donahue" -> "John Doe"
// "(123)098-7654" -> "(007)123-4567"
// "janed@example.com" -> "johnd@example.com"
doc.replaceText( {text: "Jane Donahue"}, "John Doe");
doc.replaceText( {text: "(123)098-7654"}, "(007)123-4567");
doc.replaceText( {text: "janed@example.com"}, "johnd@example.com");
// "13-Dec-20 22:16:00" -> date now
// "13-Dec-22 22:16:00" -> date now + 2 years
const termStart = new Date();
const termEnd = new Date(termStart);
termEnd.setDate(termEnd.getDate() + 365 * 2);
doc.replaceText( {text: "13-Dec-20 22:16:00"}, termStart.toLocaleString("en-US", {hour12: false}));
doc.replaceText( {text: "13-Dec-22 22:16:00"}, termEnd.toLocaleString("en-US", {hour12: false}));
// For reference, add time stamp page footer on all pages:
for (i = 0; i < doc.pages.count; ++i) {
const page = doc.pages.getAt(i);
const ctx = page.context;
const margin = ctx.resolution / 2;
ctx.drawText({ text: `Modified on ${new Date().toLocaleString()}, DsPdfJS v${ds.DsPdf.instance.version}`, fontSize: 10, foreColor: 'DimGray' }, margin, ctx.height - margin);
}
return doc;
}
Redact Annotations and Apply Redacts
DsPdfJS includes support for redact annotations and permanent redaction workflows, making it possible to mark sensitive content for removal and then apply those redactions directly to the PDF. This is especially useful for compliance, privacy, and secure document-sharing scenarios where visual masking alone is not enough and content must be actually removed from the file. The core annotation type is RedactAnnotation, which can define a redaction area and optional overlay settings such as fill color, border color, justification, and overlay text.
After annotations are added, developers use PdfDocument.redact() to apply them and permanently remove the affected content. DsPdfJS also provides RedactOptions for controlling how redaction is performed, including image handling, unreadable object behavior, precision, and render options. This makes it possible to build both simple “mark and apply” redaction workflows and more advanced scenarios such as removing targeted link areas or applying document-wide cleanup with controlled rendering behavior.

const ds = window.DocSol;
async function createPdf()
{
// Create PDF doc object & load in PDF file
const doc = ds.PdfDocument.load(await loadFileAsArray('pdfs/SlidePages.pdf'))
//Create redact annotation and set redaction area
const redact = new ds.RedactAnnotation();
Object.assign(redact, {
rect: { x: 16, y: 16, width: 280, height: 300 },
page: doc.pages.getAt(0),
overlayText: `This content has been redacted by DsPdfJS v${ds.DsPdf.instance.version} on ${new Date().toLocaleString()}`,
overlayFillColor: "PaleGoldenrod",
});
// Apply redaction
doc.redact();
return doc;
}
AcroForms
DsPdfJS includes support for AcroForms, allowing JavaScript developers to create interactive PDF forms from scratch or load existing forms and update them programmatically. This makes it possible to build workflows around form generation, form filling, and field inspection entirely in JavaScript, covering common field types such as text fields, checkboxes, radio buttons, combo boxes, list boxes, signature fields, and buttons.
The main entry point is the document’s acroForm object, which exposes the fields collection for adding, reading, and updating form fields. Developers can create fields by adding typed field definitions to doc.acroForm.fields, configure widget appearance and actions, and later load an existing PDF form and iterate through its fields to inspect or modify values. DsPdfJS also supports AcroForm.calculationOrder, giving developers control over which fields are recalculated when values change.

const ds = window.DocSol;
async function createPdf() {
const doc = new ds.PdfDocument();
const page = doc.pages.addNew();
const ctx = page.context;
const inch = ctx.resolution;
const font = ds.Font.getPdfFont(ds.StandardPdfFont.Times);
const fontSize = 14;
const tf = new ds.Format({ fontSize, foreColor: "Black" });
const x = ctx.resolution;
let y = ctx.resolution;
const fldOffset = inch * 2;
const fldHeight = fontSize * 1.2;
const dY = inch / 2;
// Text field:
ctx.drawText({ text: "Text field:", format: tf }, x, y);
{
doc.acroForm.fields.add({
type: "text",
name: "fldText",
value: "Initial text field value",
defaultValue: "Default text field value",
widget: {
page,
rect: { x: x + fldOffset, y, width: inch * 3, height: fldHeight },
defaultAppearance: { font, fontSize }
}
});
}
y += dY;
// Checkbox:
ctx.drawText({ text: "Checkbox:", format: tf }, x, y);
{
doc.acroForm.fields.add({
type: "checkbox",
name: "fldCheckbox",
checked: true,
defaultChecked: true,
widget: {
page,
rect: { x: x + fldOffset, y, width: fldHeight, height: fldHeight },
}
});
}
y += dY;
// Radio button:
ctx.drawText({ text: "Radio button:", format: tf }, x, y);
{
doc.acroForm.fields.add({
type: "radiobutton",
name: "fldRadio",
value: 1,
defaultValue: 0,
widgets:[
{ page, rect: { x: x + fldOffset, y, width: fldHeight, height: fldHeight } },
{ page, rect: { x: x + fldOffset, y: y + fldHeight * 1.2, width: fldHeight, height: fldHeight } },
{ page, rect: { x: x + fldOffset, y: y + (fldHeight * 1.2) * 2, width: fldHeight, height: fldHeight } },
]
});
}
y += fldHeight * 3 * 1.2 + fldHeight;
// CombTextField:
ctx.drawText({ text: "CombText field:", format: tf }, x, y);
{
doc.acroForm.fields.add({
type: "spacedtext",
name: "fldCombText",
value: "123",
defaultValue: "1234567890",
widget: {
page,
rect: { x: x + fldOffset, y, width: inch * 3, height: fldHeight },
defaultAppearance: { font, fontSize }
}
});
}
y += dY;
// Combo-box:
ctx.drawText({ text: "Combo box:", format: tf }, x, y);
{
doc.acroForm.fields.add({
type: "combobox",
name: "fldComboBox",
items: [ "ComboBox Choice 1", "ComboBox Choice 2", "ComboBox Choice 3"],
value: 2,
defaultValue: 0,
widget: {
page,
rect: { x: x + fldOffset, y, width: inch * 3, height: fldHeight },
defaultAppearance: { font, fontSize }
}
});
}
y += dY;
// List box:
ctx.drawText({ text: "List box:", format: tf }, x, y);
{
doc.acroForm.fields.add({
type: "listbox",
name: "fldListBox",
items: [ "ListBox Choice 1", "ListBox Choice 2", "ListBox Choice 3"],
selectedIndexes: [0, 2],
defaultSelectedIndexes: [0],
multiSelect: true,
widget: {
page,
rect: { x: x + fldOffset, y, width: ctx.resolution * 2.5, height: ctx.resolution },
defaultAppearance: { font, fontSize }
}
});
}
y += ctx.resolution + dY;
// Signature field:
ctx.drawText({ text: "Signature field:", format: tf }, x, y);
{
doc.acroForm.fields.add({
type: "signature",
name: "fldSignature",
alternateName: "All fields locked when the document is signed",
lockedFields: { type: ds.SignatureLockedFieldsType.All },
widget: {
page,
rect: { x: x + fldOffset, y: y - dY / 4, width: inch * 2, height: dY },
defaultAppearance: { font, fontSize },
buttonAppearance: { caption: "Click to sign", },
border: { width: 0.5, color: "DarkSeaGreen" }
}
});
}
y += dY;
// Buttons:
ctx.drawText({ text: "Push buttons:", format: tf }, x, y);
// Submit form button:
{
doc.acroForm.fields.add({
type: "button",
name: "btnSubmit",
alternateName: "Click to submit the form",
widget: {
page,
rect: { x: x + fldOffset, y, width: inch, height: fldHeight },
defaultAppearance: { font, },
buttonAppearance: { caption: "Submit", },
activate: new ds.ActionSubmitForm("Sample Form Submit URI"),
}
});
}
// Reset form button:
{
doc.acroForm.fields.add({
type: "button",
name: "btnReset",
alternateName: "Click to reset the form",
widget: {
page,
rect: { x: x + fldOffset + inch * 1.5, y, width: inch, height: fldHeight },
defaultAppearance: { font, },
buttonAppearance: { caption: "Reset", },
highlighting: ds.HighlightingMode.Invert,
activate: new ds.ActionResetForm(),
}
});
}
drawFooter(ctx, ctx.resolution);
return doc;
}
Encryption and Permissions
DsPdfJS includes support for PDF encryption and document permissions, allowing JavaScript developers to secure PDF files with passwords and control what recipients are allowed to do with the document. This is essential for workflows that require protected distribution, restricted printing, limited editing, or controlled content copying.
The main APIs here are EncryptOptions for applying security settings and PdfDecryptionOptions for opening protected files. Developers can use doc.security.setEncryptOptions() to set the encryption level, choose whether metadata is encrypted, define a user password, and apply permission settings such as printing or editing restrictions. When loading encrypted files, PdfDocument.load() can use decryption options such as a password, raw password bytes, and error-handling behavior for invalid passwords or unsupported security handlers. DsPdfJS also supports lower-level security handler workflows, including handlers such as StandardSecurityHandlerRev6, for more advanced control over password and permission behavior.

const ds = window.DocSol;
function createPdf()
{
const doc = new ds.PdfDocument();
// Set the required document restrictions (a suitable security handler revision
// will be created automatically):
doc.security.setEncryptOptions({
encryptionLevel: ds.EncryptionLevel.RC128,
permissions: {
copyContent: false,
printingPermissions: ds.PrintingPermissions.Disabled,
editingPermissions: ds.EditingPermissions.Disabled
}
});
/* Alternatively, you may create a specific revision of the standard security handler
* and set its options directly:
// Create a Rev4 security handler and specify some restrictions:
var ssh4 = ds.StandardSecurityHandlerRev4.create();
ssh4.copyContent = false;
ssh4.printingPermissions = ds.PrintingPermissions.Disabled; // TBD! printingPermissions
ssh4.editingPermissions = ds.EditingPermissions.Disabled;
doc.security.encryptHander = ssh4;
*/
// Add a page to the PDF with some explanatory text:
const ctx = doc.newPageContext();
const res = ctx.resolution;
const tf1 = new ds.Format({ fontSize: 20, foreColor: "Brown" });
const tf2 = new ds.Format({ fontSize: 16, foreColor: "Blue" });
const tl = new ds.Layout({
marginAll: ctx.resolution,
runs: [
{
text: "Document Restrictions.\n\n",
format: tf1
},
{
text:
"This document has the following restrictions imposed using StandardSecurityHandlerRev4:\n" +
" - content copying is not allowed;\n" +
" - printing is not allowed;\n" +
" - document assembly is not allowed.\n" +
"\nSee index.js for details on how to programmatically set document restrictions.",
format: tf2
},
],
maxWidth: ctx.width,
maxHeight: ctx.height,
});
ctx.drawLayout(tl, 0, 0);
// Add page footer with time stamp and DsPdfJS version:
ctx.drawText({ text: `Generated on ${new Date().toLocaleString()}, DsPdfJS v${ds.DsPdf.instance.version}`, fontSize: 10, foreColor: 'DimGray' }, res, ctx.height - res);
return doc;
}
Optimization and Compression
DsPdfJS includes support for PDF optimization and compression, giving developers control over file size and save behavior when generating or modifying PDF documents. This is especially useful for delivery scenarios where smaller files improve storage efficiency, upload speed, and web performance.
The main APIs here are CompressionLevel, PdfStreamHandling, and SavePdfOptions. Developers can choose whether compression should prioritize speed, balanced output, or the smallest possible file, and they can control how existing streams in a loaded document are handled when saving. For example, streams can be copied as-is, recompressed using the document’s compression settings, or minimized for the best possible size reduction. These options are applied through savePdf(), giving JavaScript developers a flexible way to tune output for performance or compactness.
Font Support and Embedding
DsPdfJS includes strong support for fonts and font embedding, allowing developers to use standard PDF fonts, load custom font files, manage families through font collections, and control how text is rendered in generated documents. This is essential for maintaining visual fidelity, supporting brand typography, and ensuring text displays correctly across different PDF viewers and environments.
The main APIs here are Font and FontCollection. Developers can load fonts from files, use built-in standard PDF fonts, register multiple fonts in a collection, and let DsPdfJS resolve the best match by family and style. FontCollection also supports fallback fonts, default fonts, and font search, which makes it easier to handle mixed typography or missing glyphs. Beyond simple font loading, DsPdfJS also supports font features, bold/italic emulation, and custom drawing workflows that use either specific font objects or family-based resolution through a collection.

const ds = window.DocSol;
async function createPdf()
{
// A FontCollection lets you register multiple fonts once and then resolve them by
// family name + style (bold/italic) when drawing text. You can attach it to a Layout
// (for DrawingContext.drawLayout) or to a DrawingContext (for drawText/measureText).
const fc = new ds.FontCollection();
async function addFont(fontFileName) {
fc.addFont(ds.Font.load(await loadFileAsArray(fontFileName)));
}
await Promise.all([
addFont("fonts/NotoSerif-Regular.ttf"),
addFont("fonts/NotoSerif-Bold.ttf"),
addFont("fonts/NotoSerif-Italic.ttf"),
addFont("fonts/NotoSerif-BoldItalic.ttf"),
addFont("fonts/NotoSans-Regular.ttf"),
addFont("fonts/NotoSans-Bold.ttf"),
addFont("fonts/NotoSans-BoldItalic.ttf"),
]);
const doc = new ds.PdfDocument();
const ctx = doc.newPageContext();
const page = ctx.page;
const margin = ctx.resolution / 2;
const maxWidth = ctx.width - margin * 2;
const maxHeight = ctx.height - margin * 2;
const tl = new ds.Layout({
marginAll: margin,
maxWidth,
maxHeight,
fontCollection: fc,
});
let tf = new ds.Format({ fontFamily: "noto serif", fontSize: 16, foreColor: "DarkBlue" });
tl.append({text: "Text drawn using Noto Serif Regular font. ", format: tf});
// Setting bold/italic tells the FontCollection to resolve the best matching font
// in that family. If an exact variant isn't available, the renderer may emulate it.
tf = new ds.Format(tf, { italic: true, });
tl.append({text: "Text drawn using Noto Serif Italic font. ", format: tf});
tf = new ds.Format(tf, { bold: true, });
tl.append({text: "Text drawn using Noto Serif Bold Italic font. ", format: tf});
tf = new ds.Format(tf, { italic: false, });
tl.append({text: "Text drawn using Noto Serif Bold font. ", format: tf});
// Switch to another font family:
tf = new ds.Format(tf, { fontFamily: "noto sans", });
tl.append({text: "Text drawn using Noto Sans Bold font. ", format: tf});
tf = new ds.Format(tf, { italic: true, });
tl.append({text: "Text drawn using Noto Sans Bold Italic font. ", format: tf});
tf = new ds.Format(tf, { bold: false, italic: false, });
tl.append({text: "Text drawn using Noto Sans Regular font. ", format: tf});
ctx.drawLayout(tl, 0, 0);
// You can also assign the FontCollection to the DrawingContext so drawText(), drawLayout(),
// and measureText() can resolve fontFamily names from that collection
// (comment out the next line to confirm that the correct font won't be found):
ctx.fontCollection = fc;
ctx.drawText("Text drawn with DrawingContext.drawText() method using Noto Serif Bold font from the collection.",
new ds.Format({ fontFamily: "noto serif", fontSize: 16, foreColor: "darkgreen" }),
margin,
tl.contentRect.y + tl.contentRect.height,
page.width - margin * 2,
);
// Add a page footer with time stamp and DsPdfJS version:
drawFooter(ctx, margin * 2);
return doc;
}
Raster and Scalable Vector Image Handling
DsPdfJS includes support for both raster and scalable vector image handling, allowing JavaScript developers to load, draw, clip, and save image content as part of PDF generation workflows. In v9.1, DsPdfJS supports JPEG, PNG, and SVG image scenarios, making it possible to work with both common raster formats and scalable vector artwork when building PDF documents.
For raster images, the main API is the Image class, which can load JPEG or PNG image data, expose image dimensions and type, convert image content to a bitmap, and save image data back out when needed. Developers can then draw images onto PDF pages using the drawing context, with support for scaling, clipping, opacity, alignment, and repeated placement. This makes it easy to handle common tasks such as inserting photos, placing logos, creating cropped image views, or layering semi-transparent images into document layouts.
For SVG workflows, DsPdfJS also provides APIs for drawing SVG content through its SVG drawing support, making it possible to place vector artwork into PDF output while preserving resolution independence. Together, these image APIs give developers a flexible way to combine raster and vector graphics in JavaScript-based PDF generation.

const ds = window.DocSol;
async function createPdf() {
const doc = new ds.PdfDocument();
const img = ds.Image.load(await loadFileAsArray("img/wargravepink.jpg"));
const bmpFull = img.toBitmap();
const scale = 0.5; // draw at half pixel size
// Note about PDF/page/image units:
// - Page coordinates are in “points” (pt). By default, ctx.resolution is 72 pt/in (PDF points),
// but you can set ctx.resolution to another value if you want a different coordinate scale.
// - Images use pixels (px).
// - If you treat images as 96 dpi, convert with pt = px * (ctx.resolution / 96) before scaling.
// Page 1:
let ctx = doc.newPageContext();
const margin = ctx.resolution / 2;
let top = margin;
// Draw using 0.5 points per source pixel (≈ 67% of 96-dpi size):
ctx.drawImage(img, margin, top, img.width * scale, img.height * scale);
top += img.height * scale + 36;
// Draw a clipped portion of the image:
ctx.drawImage(
img,
margin,
top,
img.width * scale,
img.height * scale,
{ clipBounds: { x: margin + 90, y: top + 90, width: 150, height: 100 } }
);
drawFooter(ctx, margin);
// Page 2:
ctx = doc.newPageContext();
top = margin;
// Clip region specified in page units above; convert to bitmap pixel units:
const clipPx = { x: 90 / scale, y: 90 / scale, width: 150 / scale, height: 100 / scale };
const bmp = bmpFull.clip(clipPx);
ctx.drawImage(bmp, margin, top, bmp.width / 2, bmp.height);
top += bmp.height * 1.5;
ctx.drawImage(bmp, margin, top, bmp.width, bmp.height / 2);
drawFooter(ctx, margin);
return doc;
}
Annotations
DsPdfJS includes broad support for PDF annotations, allowing JavaScript developers to add comments, markup, links, attachments, shapes, stamps, multimedia, watermarks, widgets, and redaction markers to PDF documents. Supported types include common review and markup annotations such as TextAnnotation, FreeTextAnnotation, TextMarkupAnnotation, SquareAnnotation, CircleAnnotation, LineAnnotation, InkAnnotation, PolygonAnnotation, PolyLineAnnotation, StampAnnotation, LinkAnnotation, FileAttachmentAnnotation, and RedactAnnotation, along with specialized types such as RichMediaAnnotation, SoundAnnotation, WatermarkAnnotation, and WidgetAnnotation.
Many of these annotation types derive from MarkupAnnotation, which provides the shared foundation for comment-style and review-style annotations. In practice, developers can create annotation objects, set properties such as content, color, position, and related appearance settings, and then add them to a page through the page’s annotations collection. This makes DsPdfJS well suited for workflows involving document review, collaboration, commenting, visual markup, links, and interactive PDF experiences.

const ds = window.DocSol;
function createPdf()
{
const doc = new ds.PdfDocument();
const page = doc.pages.addNew();
const ctx = page.context;
const margin = ctx.resolution;
const gap = margin / 2;
const maxWidth = ctx.width - margin * 2;
let ipX = margin, ipY = margin;
const tf = new ds.Format({ fontSize: 16, font: ds.Font.getPdfFont(ds.StandardPdfFont.Times) });
const tl = new ds.Layout({
defaultFormat: tf,
maxWidth,
});
function drawNote(text) {
tl.clear();
tl.appendLine({ text });
ctx.drawLayout(tl, ipX, ipY);
ctx.drawRect(ipX, ipY, tl.contentWidth, tl.contentHeight, {lineColor: "gray"});
}
drawNote("This sample demonstrates some types of annotattions that can be created with DsPdfJS.");
ipY += tl.contentHeight + gap;
// A text annotation (red):
tl.clear();
drawNote("A red text annotation is placed to the right of this note.");
const textAnnot = new ds.TextAnnotation(); //ds.getCurrentObjectManager());
Object.assign(textAnnot, {
userName: "Jaime Smith",
contents: "This is a red TextAnnotation.",
rect: { x: ipX + tl.contentWidth, y: ipY, width: 100, height: 50 },
color: "Red",
});
page.annotations.add(textAnnot);
// A reply to the previous annotation:
const textAnnotReply = new ds.TextAnnotation();
Object.assign(textAnnotReply, {
userName: "Jane Donahue",
contents: "This is a reply to the first annotation.",
referenceAnnotation: textAnnot,
referenceType: "R",
});
page.annotations.add(textAnnotReply);
ipY += tl.contentHeight + gap;
// Open text annotation (green):
drawNote("An initially open green text annotation is placed to the right of this note.");
const textAnnotOpen = new ds.TextAnnotation();
Object.assign(textAnnotOpen, {
open: true,
userName: "Jaime Smith",
contents: "This is an initially open annotation (green).",
rect: { x: ipX + tl.contentWidth, y: ipY, width: 100, height: 50 },
color: "green",
});
page.annotations.add(textAnnotOpen);
ipY += tl.contentHeight + gap;
// Free text annotation:
drawNote("A blue free text annotation is placed below and to the right, with a callout going from it to this note.");
const calloutLine = [
{x: ipX + tl.contentWidth / 2, y: ipY + tl.contentHeight},
{x: ctx.width - 220, y: ipY + tl.contentHeight + gap}
];
ipY += tl.contentHeight + gap;
const freeAnnot = new ds.FreeTextAnnotation();
Object.assign(freeAnnot, {
contents: "This is a free text annotation with a callout line going to the note on the left.",
rect: { x: ctx.width - 220, y: ipY, width: 200, height: 50 },
calloutLine,
color: "LightSkyBlue",
});
page.annotations.add(freeAnnot);
ipY = freeAnnot.rect.y + freeAnnot.rect.height + gap;
// Free text annotation with rich text:
const freeRichTextAnnot = new ds.FreeTextAnnotation();
Object.assign(freeRichTextAnnot, {
richText: "<body><p>This is another <i>free text annotation</i>, with <b><i>Rich Text</i></b> content.</p>" +
"<p>Even though a <b>free text</b> annotation displays text directly on a page, " +
"as other annotations it can be placed outside the page's bounds.</p></body>",
rect: { x: ipX - margin * 2, y: ipY, width: margin * 5, height: margin },
calloutLine,
color: "LightSalmon",
});
page.annotations.add(freeRichTextAnnot);
ipY = freeRichTextAnnot.rect.y + freeRichTextAnnot.rect.height + gap;
// Square annotation around a note:
drawNote("A square annotation drawn with a 3pt wide orange line around this note has a rich text associated with it.");
const sauareAnnot = new ds.SquareAnnotation();
Object.assign(sauareAnnot, {
userName: "Jane Donahue",
contents: "This is a free text annotation with a callout line going to the note on the left.",
rect: { x: ipX - 7, y: ipY - 7, width: tl.contentWidth + 14, height: tl.contentHeight + 14},
lineWidth: 3,
color: "Orange",
richText: "<body><p>This <b><i>rich text</i></b> is associated with the square annotation around a text note.</p></body>"
});
page.annotations.add(sauareAnnot);
// Add page footer with time stamp and DsPdfJS version:
ctx.drawText({ text: `Generated on ${new Date().toLocaleString()}, DsPdfJS v${ds.DsPdf.instance.version}`, fontSize: 10, foreColor: 'DimGray' }, margin, ctx.height - margin);
return doc;
}