Skip to content

Images

Embed images directly from byte arrays. JPEG and PNG are the primary raster paths, with additional helpers for BMP, GIF, JPEG2000, JBIG2, TIFF, WebP, and SVG. PNG transparency masks and alpha-channel soft masks are preserved.

Auto-detecting the format

page.image() sniffs the raster format from the data's magic bytes (PNG, JPEG, GIF, BMP, TIFF, WebP, JPEG 2000) and dispatches to the right decoder — handy when the format isn't known ahead of time:

ts
import { readFile } from "node:fs/promises";

page.image(await readFile("logo"), { x: 56, y: 600, width: 120, height: 60, altText: "Logo" });

It throws UNSUPPORTED_IMAGE_FORMAT if the bytes match no known raster format. For SVG (text, not raster) use page.svg(). Use the format-specific methods below when you want a specific decoder or format-only options.

JPEG

ts
import { readFile } from "node:fs/promises";

const jpegBytes = await readFile("photo.jpg");
page.jpeg(jpegBytes, {
  x: 56,
  y: 500,
  width: 200,
  height: 150
});

The encoder reads dimensions from the JPEG SOF marker, so width/height default to the native size when omitted.

PNG

ts
const pngBytes = await readFile("logo.png");
page.png(pngBytes, {
  x: 56,
  y: 700,
  width: 64,
  height: 64
});

8-bit grayscale, RGB, indexed, and RGBA PNGs are supported. tRNS palette transparency and full alpha channels are written as image soft masks.

Aspect ratio

Pass only width or height to scale proportionally:

ts
page.png(pngBytes, { x: 56, y: 700, width: 64 });

Additional Image Formats

Beyond JPEG and PNG, the library supports several other image formats through dedicated methods:

  • BMP (24-bit and 32-bit) — Windows bitmap format. 32-bit masks are written as image soft masks.
  • JPEG2000 (JPXDecode) — Available via page.jpeg2000(). Decoder reads the JP2 header for dimensions.
  • JBIG2 — Bi-level (black-and-white) compression ideal for scanned documents. Use page.jbig2() with monochrome data.
  • TIFF (LZW) — Baseline TIFF with LZW compression. Multi-page TIFFs extract the first page only.
  • WebP (VP8L lossless) — Lossless WebP via page.webp(). WebP lossy is not supported; use lossless only.
  • GIF — First frame only, with transparency preserved when a transparent color index is present.
  • SVG — Vector conversion via page.svg(). Rasterized to a page-relative coordinate space; text elements may be outlined.

CMYK JPEG

JPEG images in the CMYK color space are written with a DeviceCMYK color space instead of DeviceRGB:

ts
page.jpeg(cmykJpegBytes, { x: 56, y: 500, width: 200 });
// Written as /ColorSpace /DeviceCMYK, /Decode [0 1 0 1 0 1 0 1]

Indexed PNG palette expansion

Indexed (palette-based) PNGs are automatically expanded to direct-color RGB before embedding. The palette entries are written inline in the PDF, and no transparency from the palette table is lost—tRNS chunks expand into a full alpha soft mask.

EXIF orientation

JPEG and PNG images with EXIF orientation metadata are automatically rotated to the correct display orientation before embedding. The encoder reads the Orientation tag (TIFF/EXIF IFD0) and applies the corresponding transform, so the image appears upright without manual rotation.

Tagged figures and alt text

For PDF/UA output, supply altText so screen readers can announce the image:

ts
page.flow({ font })
  .png(logoBytes, { width: 32, altText: "Company logo" });

Low-level page.png() and page.jpeg() accept altText and structure.boundingBox when used inside a tagged document. Decorative images should be marked as artifacts via structure: { tag: "Artifact" }.

Released under the ISC license.