Takumi

Image loading & emoji

Load remote, pre-fetched, and raw-pixel images, render emoji, and tune fetch limits and caches in Takumi.

Takumi fetches the remote images your markup references, accepts images you fetch or decode yourself, and turns emoji into images. Fetch limits, retries, caches, and decode limits come after these, at the end of the page.

External images

render() and ImageResponse fetch every remote http:// or https:// image the tree draws once its styles apply:

  • an <img> src
  • background-image, mask-image, and list-style-image, whether style, tw, css, a <style> element, or a ::before rule sets them
  • images an animation's @keyframes switch to

An image under display: none is not fetched. A relative URL such as /logo.png is fetched only through your own fetch, which can resolve it.

When user input can reach the markup, set allowUrl, as URLs from user input describes.

Share a fetchCache across renders to reuse downloaded bytes and pending requests:

Share downloaded image bytes
import {  } from "takumi-js";

const  = < ="https://example.com/image.png" />;

const  = new <string, <>>();

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

fetchCache takes a Map<string, Promise<ArrayBuffer>> or any object with the same get, set, and delete methods. Values are promises, not raw buffers.

Emoji images from the emoji option are cached across renders without a fetchCache, up to 8 MB per fetch function.

A plain Map never evicts entries. If each render uses a different URL, pass a bounded cache such as an LRU, or leave fetchCache out.

Pre-fetched images

Give images a key so the renderer never fetches them. Use the key in any src or CSS url().

Load named image sources
import {  } from "takumi-js/response";

export function (: ) {
  return new (< />, {
    : [
      {
        : "my-logo",
        : () => (new ("/logo.png", .)).(() => .()),
      },
      {
        : "background",
        : () => (new ("/background.png", .)).(() => .()),
      },
    ],
  });
}

function () {
  return (
    <
      ={{
        : "url(background)",
      }}
    >
      < ="my-logo" />
    </>
  );
}

data is raw bytes or a function that returns them. Takumi skips fetching any remote URL that already has an entry.

Raw pixels

Pass raw RGBA pixels instead of encoding a PNG first, and Takumi skips decoding. The Bitmap helper renders a row-major buffer of width * height * 4 bytes as an <img>. This example fills a 64 × 64 image with opaque blue:

Render raw RGBA pixels
import {  } from "takumi-js";
import {  } from "takumi-js/helpers/jsx";

const  = new (64 * 64 * 4);

for (let  = 0;  < .;  += 4) {
  .([59, 130, 246, 255], );
}

const  = await (< ={64} ={64} ={} />, {
  : 64,
  : 64,
});

Set premultiplied when the bytes already have premultiplied alpha. Takumi then uses them as they are. Outside JSX, an image node's src takes the same { width, height, data, premultiplied? } object.

Emoji

takumi-js turns emoji into images by default. It splits each emoji out of the text and fetches its SVG from a CDN, using Twemoji unless you pick another set.

Dynamic fetching

Set emoji to choose the set. render, renderSvg, renderAnimation, measure, and ImageResponse all take it, and the CDN values match satori's. Each emoji's SVG comes from jsDelivr, at the version the table lists:

ValueEmoji setFetched from
twemoji (default)Twemojijdecked/twemoji 17.0.2
blobmojiBlobmoji@svgmoji/blob 2.0.0
notoNoto Emojigooglefonts/noto-emoji v2.051
openmojiOpenMoji@svgmoji/openmoji 2.0.0
fluentFluent Emoji, colorshuding/fluentui-emoji-unicode 7a40f1a
fluentFlatFluent Emoji, flatshuding/fluentui-emoji-unicode 7a40f1a
from-fontGlyphs from a color font you loadNo fetch. See COLR / bitmap fonts
Fetch emoji images
import {  } from "takumi-js/response";

export function () {
  return new (< ="flex justify-center items-center text-3xl">Hello 👋😁</>, {
    : "noto", 
  });
}

Emoji detection follows the Unicode presentation rules. A pictograph that defaults to text presentation, such as ‼ or ▶, stays text and renders with your fonts. Add U+FE0F after it to force the emoji image. Add U+FE0E after an emoji to keep the text glyph.

On your own renderer, prepare() splits emoji and fetches their images the same way.

COLR / bitmap fonts

Takumi draws emoji from color fonts, either COLR fonts such as Twemoji-COLR or bitmap fonts such as Noto Color Emoji. A COLR file is much smaller than a bitmap font. The glyphs come from the loaded font, so no emoji request goes out.

To use a color font, do both of these:

  • Register the font through fonts.
  • Set emoji: "from-font".

Variation selectors take priority over font order. A code point followed by U+FE0F renders as a color emoji, even when a text font comes first in the stack. A code point followed by U+FE0E renders as a monochrome glyph, even when a color font comes first. Bare code points follow stack order, as in browsers.

Prepare on your own renderer

A renderer you create yourself fetches nothing on its own. Its prepare() does what render() does before drawing. It styles the source, fetches the images it draws, emoji included, and loads the font subsets its text uses. Pass the result to the renderer's render, renderSvg, or measure:

Prepare, then render
const  = new ();
const  = new <string, <>>();

const  = await .(, {
  : 1200,
  : 630,
  : "twemoji",
  : {  },
});

const  = await .(, { : "webp" });
  • prepare takes the layout options of render, such as the size, css, lang, emoji, and fonts, plus images with the same fetch limits. Rendering a prepared source takes only the output options, so the layout cannot change between the two calls.
  • With your own fetch, a relative URL such as /logo.png reaches it, so it can resolve the path and apply its own checks. Without one, only http:// and https:// URLs are fetched.
  • A prepared source renders on any renderer from the same package. A renderer that no longer holds its fonts loads them again.

PdfRenderer from takumi-pdf and Painter from takumi-paint have the same prepare. A PDF's header, footer, and page bands count as part of the document, and rendering a prepared PDF takes the file options such as metadata, outline, and pdfa.

Fetch limits

Limit image fetches
import {  } from "takumi-js";

const  = < ="https://example.com/image.png" />;

const  = await (, {
  : {
    : 3000,
    : 4 * 1024 * 1024,
    : () => new (). === "example.com",
  },
});

... (+124 lines) [see remaining: rtk proxy git show feat/render-needs-bindings:docs/content/docs/images.mdx | tail -n +188]

Last updated on