Skip to content

Print, export, and watermarks

Use the current annotations to export a PDF or Excel workbook, prepare an ordinary or password-protected PDF for printing, and control where a document watermark appears.

TIP

Core generates the output; your application decides whether to download it, upload it, or open the system print dialog.

Export an annotated PDF

ts
import { downloadBlob } from '@inklayer-dev/core'
import { buildAnnotatedPdf } from '@inklayer-dev/core/export/pdf'

const annotations = core.annotations.repository.getAll()
const watermark = core.viewer.getWatermark()

const pdfBytes = await buildAnnotatedPdf(sourceBytes, annotations, {
  strategy: 'strict',
  annotationTypes: core.annotationTypes,
  ...(watermark === null ? {} : { watermark })
})

downloadBlob({
  content: pdfBytes,
  filename: 'review.pdf',
  mimeType: 'application/pdf'
})

sourceBytes must contain the original PDF bytes, which the application retains or retrieves when needed. The exporter writes the current annotations into a new PDF while preserving the original document's vector content. Pass core.annotationTypes so custom annotation types can also be exported.

External PDF applications show the annotation /T title. Core formats it as Author · #N when a referenceNumber is available, while /NM keeps the stable annotation ID used for relationships. Override only the visible title when your product needs another convention:

ts
const pdfBytes = await buildAnnotatedPdf(sourceBytes, annotations, {
  annotationTitle: annotation => `Review ${annotation.referenceNumber ?? '—'}`
})

InkLayer exports also retain the original author, reference number, and structured references as round-trip metadata. Changing annotationTitle does not change permissions or reference targets.

buildAnnotatedPdf() only returns bytes. Downloading, naming, or uploading the result is a separate application decision. The default strict strategy rejects an invalid or unsupported annotation; lenient skips that entry and reports it through the optional onWarning callback. Password-protected source bytes cannot be exported by this client-side vector path.

Use buildPrintablePdf() for an unencrypted PDF when you want to preserve text, links, forms, and vector content:

ts
import { printPdfBlob } from '@inklayer-dev/core'
import { buildPrintablePdf } from '@inklayer-dev/core/export/pdf'

const watermark = core.viewer.getWatermark()

const printable = await buildPrintablePdf(
  sourceBytes,
  core.annotations.repository.getAll(),
  {
    annotationTypes: core.annotationTypes,
    ...(watermark === null ? {} : { watermark })
  }
)

await printPdfBlob({ content: printable })

buildPrintablePdf() applies the watermark's print target, while buildAnnotatedPdf() applies its export target. printPdfBlob() receives an object containing the generated bytes and owns the temporary iframe and object URL used to open the browser's print dialog.

After PDF.js has opened a password-protected document, generate a temporary rasterized PDF from the current Viewer:

ts
import { buildSecureRasterPrintPdf, printPdfBlob } from '@inklayer-dev/core'

const printable = await buildSecureRasterPrintPdf({
  viewer: core.viewer,
  annotations: core.annotations,
  pixelRatio: 2,
  onProgress: (completed, total) => updateProgress(completed, total)
})

await printPdfBlob({ content: printable })

This browser-only path includes the current annotations and print watermark. It rejects documents that disallow printing and limits the pixel ratio to 1 when the document permits low-resolution printing only.

The resulting PDF is temporary, unencrypted, and made entirely of page images. Selectable text, links, forms, and vector detail are flattened. Use it only to open the print dialog; do not offer it as a replacement download or export for the protected document. A protected vector export requires a trusted backend that can decrypt, process, and re-encrypt the document.

Configure a watermark

ts
import type { PdfWatermarkSpec } from '@inklayer-dev/core'

const watermark: PdfWatermarkSpec = {
  text: `${currentUser.name} · ${documentId}`,
  layout: 'repeated',
  opacity: 0.12,
  rotation: -28,
  targets: {
    viewer: true,
    print: true,
    export: true,
    thumbnails: false
  }
}

core.viewer.setWatermark(watermark)

Configure the watermark before loading the document so it appears when Page Flow first renders the pages. viewer, print, and export independently control the Viewer, printed PDF, and exported PDF. By default, Viewer and print watermarks are enabled, while export and thumbnail watermarks are disabled.

targets.thumbnails is part of the watermark configuration, but the current renderThumbnail() implementation does not apply watermarks. Setting this flag to true does not currently watermark generated thumbnails.

For Chinese or other characters unsupported by the default PDF font, provide TrueType or OpenType font bytes when generating a vector PDF:

ts
const response = await fetch('/fonts/NotoSansSC-Regular.ttf')
const watermarkFontBytes = new Uint8Array(await response.arrayBuffer())

const pdfBytes = await buildAnnotatedPdf(sourceBytes, annotations, {
  watermark,
  watermarkFontBytes,
  annotationTypes: core.annotationTypes
})

The same watermarkFontBytes option is supported by buildPrintablePdf(). Viewer and raster-print watermarks are drawn by the browser and use its available fonts instead. Watermarks discourage casual redistribution, but they are not tamper-resistant access control; enforce sensitive-document policy on a trusted backend as well.

Export annotations to Excel

ts
import { downloadBlob } from '@inklayer-dev/core'
import { buildAnnotationWorkbook } from '@inklayer-dev/core/export/excel'

const workbook = await buildAnnotationWorkbook(
  core.annotations.repository.getAll()
)

downloadBlob({
  content: workbook,
  filename: 'annotations.xlsx',
  mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})

The workbook contains separate annotation and comment sheets. Worksheet names and column labels can be localized through buildAnnotationWorkbook() options; annotation types, review statuses, and reference identifiers retain their original values.

printPdfBlob() and downloadBlob() are browser-specific helpers. For Electron, mobile WebViews, server rendering, or custom file services, provide your own print or download implementation through createPrintCapability() or createDownloadCapability().

Released under the MIT License.