Takumi

Fonts & images

Load fonts and image bytes for PDF rendering, including SVG charts and offline assets.

Pass fonts through fonts and image bytes through images. The renderer fetches neither on its own. Font URL loaders and googleFonts() make their own requests, and you fetch document images before rendering.

Fonts

Fonts
import {  } from "takumi-pdf";

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

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

fonts takes font URLs, raw bytes, descriptors, or googleFonts() entries. fontFamilies sets the fallback chain. A reused renderer loads each font once.

For offline renders, bundle font files. Google Fonts requests use the shared fetch limits and retries.

Coverage

The renderer does not read system fonts. Its only built-in font is Geist, a last-resort face for Latin text. By default, a character that no registered font covers fails the render, and the error names the character and its codepoint.

Register fonts for every script you use. Google Fonts can split accented letters between its latin and latin-ext subsets.

Family names

Quote a family name when one of its words starts with a digit, such as fontFamily: '"Source Serif 4"'. Unquoted, Source Serif 4 is not a valid font-family value. The declaration is dropped and the text falls back to the next family.

Uncovered text

uncoveredText sets what happens to a character that no registered font covers:

ValueResult
"error" (default)Fails the render, naming each character and its codepoint.
"placeholder"Draws the font's glyph 0, which the font may leave empty.
"blank"Draws nothing.

Neither "placeholder" nor "blank" reflows the line. The character keeps the width it had during layout.

Render with uncovered characters
import {  } from "takumi-pdf";

const  = await (, { : "placeholder" });

Standards forbid the placeholder

Every PDF/A level and both PDF/UA levels forbid glyph 0. "placeholder" fails the render with any pdfa level, tagged: "ua1", or tagged: "ua2". The error names the uncovered characters and the standard. Use "blank" there. See PDF/A and PDF/UA.

What copied text keeps

Whether an uncovered character survives in copied text depends on its shaping cluster. This holds for "placeholder" and "blank" alike.

Uncovered characterCopied text
On its ownNothing. A PDF carries no Unicode mapping for glyph 0.
A combining mark on a covered letterThe mark, through the letter it shares a cluster with.

Images

Pass the bytes for each image URL in the document. The renderer does not fetch them:

Images
import {  } from "takumi-pdf";

const  = await ();
if (!.) throw new (`Logo request failed: ${.}`);
const  = new (await .());

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

To fetch every remote image in a tree at once, use prepareImages().

Formats

SourceIn the PDF
SVGVector paths and gradients. Parts vectors cannot express, such as filters and embedded bitmaps, rasterize at 2× their placed size.
PNGEmbedded as an image
JPEGEmbedded as the bytes you passed, keeping their compression
WebPEmbedded as an image
GIFRejected: the PDF build ships no GIF decoder

Identical raster images are embedded once.

Filters

A CSS color filter on an image needs decoded pixels, and the PDF build decodes only PNG. A filtered JPEG or WebP image fails the render.

PDF output also rejects filter: blur() and drop-shadow(), naming the function in the error. Bake those effects into a raster image before rendering.

Last updated on