Takumi

Fonts & images

Embed subset fonts and pre-fetched images.

Fonts

Text embeds as real glyph runs with subset fonts. It stays selectable, searchable, and copyable. Pass a URL or raw bytes. You can also use the googleFonts helper:

import {  } from "takumi-pdf";

import {  } from "@takumi-rs/helpers";

const  = await (, {
  : [...(await (["Inter"])), { : "Brand Sans", : 700, :  }],
  : ["Brand Sans", "Inter", "sans-serif"],
});

fontFamilies sets the fallback chain for each render. Registered fonts deduplicate across calls that use the same renderer.

There is no system font to fall back on. A character that none of the registered fonts covers would draw nothing and leave nothing in the text layer, so render rejects it and names the character and its codepoint. Register a font covering every script the document uses. Watch the Google Fonts subsets in particular: latin and latin-ext split their coverage, so one file on its own can leave common accented characters out.

Images

The renderer never fetches over the network. Pass pre-fetched bytes for each image URL in the document:

import {  } from "takumi-pdf";

const  = new (await (await ()).());

const  = await (, {
  : [{ : , :  }],
});

SVG image sources embed as vector paths and gradients, so logos stay sharp at any zoom. Subtrees that vectors cannot express (filters, embedded bitmaps) rasterize at 2× their placed size. Raster sources embed once for each distinct pixel data.

PNG, JPEG and WebP bytes all embed. A JPEG goes in as the JPEG you passed, so the PDF carries the compression the file already had. GIF bytes are rejected: no decoder for them ships in this build.

A CSS filter needs pixels to work on, and this build decodes only PNG. An image under a filter that arrived as JPEG or WebP has none, so render rejects the document and names the image rather than leaving a hole in the page. The same goes for filter: blur() and drop-shadow(), which a PDF cannot express at all.

Runtimes

takumi-pdf is wasm-only. It runs on Node.js, Bun, and Cloudflare Workers. The module fits within the Workers free-tier size limit. Import takumi-pdf/no-init to control wasm instantiation.

Last updated on

On this page