COOLJAPAN
← All posts

OxiText 0.2.1 Released — Color Emoji Go From 0% Pixel Coverage to a Full COLRv1 Paint Graph

OxiText 0.2.1 fixes COLRv0/COLRv1 color-glyph rendering — previously 0% pixel coverage on every color emoji — into a complete paint-graph interpreter with gradients, transforms, clips, and all 28 composite modes, swaps in a Pure-Rust PNG encoder to clear the last banned dependency, and cuts font-cache overhead by up to 13,000x. The sovereign text layer for the COOLJAPAN ecosystem.

release oxitext pure-rust cooljapan noffi text typography emoji performance security

Every color emoji OxiText ever rendered was fully transparent — and nothing in the API surface told you that.

Today we released OxiText 0.2.1 — a fix release that turns COLRv0/COLRv1 color-glyph rendering from a silent no-op into a complete paint-graph interpreter, replaces its PNG dependency with a Pure-Rust encoder to close the last banned flate2/miniz_oxide link, and cuts thread-local font-cache overhead by up to 13,000x.

No png crate. No flate2. No miniz_oxide. And COLRv1’s gradients, transforms, clip lists, and all 28 composite modes now paint real pixels instead of the seven distinct outputs the old stub-based interpreter produced from sixty test glyphs. OxiText stays composed entirely from Pure-Rust crates, so it still builds as a single static binary with no system libraries and no C toolchain — this release just makes what it draws correct.

Why OxiText 0.2.1 is a game changer

Color-glyph fonts (Twemoji, Noto Emoji, and every COLR-based emoji set) look simple from the outside — layers, palettes, maybe a gradient — but the previous pipeline had two compounding bugs:

OxiText 0.2.1 ends all of that:

Technical Deep Dive: the paint pipeline, layer by layer

  1. Outline extraction. A new internal anti-aliased scanline rasterizer reads ttf-parser outlines directly (glyf/CFF/CFF2), using the same em-scale and baseline placement fontdue used, so single-layer COLRv0 output is unchanged to within a mean alpha difference under 12/255.
  2. Paint-graph interpretation (colr_paint.rs). Transform and clip stacks are threaded through every PaintColrLayers/PaintComposite/PaintGlyph recursion; gradients are sampled through the inverse of the active transform so control points stay in the right coordinate space.
  3. Compositing. Each layer renders into its own premultiplied f32 target; the 28 composite modes combine them, and the result is un-premultiplied once at the end so 8-bit rounding error doesn’t accumulate across intermediate layers.
  4. Memoization (colr_cache.rs). A thread-local LRU keyed on (Arc<[u8]> font identity, glyph id, size, palette) retains the caller’s Arc for the entry’s lifetime (a bounded content hash isn’t a safe identity here — a collision would hand back the wrong picture, not just a wrong parse). Bounded to 256 entries / 8 MiB total; a single result over 2 MiB is returned uncached. Warm lookups cost 13–15 ns in release — a 2,600–4,800x saving over repainting.

Getting Started

cargo add oxitext-raster
use oxitext_raster::render_colr_glyph_sized;

let font_data = std::fs::read("emoji-font.ttf")?;
let glyph_id: u16 = 42; // resolved via cmap/shaping for the emoji codepoint
let palette = 0; // default CPAL palette

if let Some(img) = render_colr_glyph_sized(&font_data, glyph_id, 64.0, palette) {
    // `img.rgba` is straight (non-premultiplied) RGBA, trimmed to ink.
    println!(
        "{}x{} color glyph, bearing ({}, {})",
        img.width, img.height, img.bearing_x, img.bearing_y
    );
}
# Ok::<(), Box<dyn std::error::Error>>(())

render_colr_glyph_sized derives the bitmap from the glyph’s own paint box — its ClipList entry, else the base outline’s bbox, else a margin around the em — rather than a fixed preview square, so gradients and transforms that paint outside a naive 1em box aren’t clipped. Drawing the same emoji every frame (a caption renderer, for instance)? Reach for render_colr_glyph_sized_cached instead, which memoizes the paint graph per thread and returns a shared Arc<ColorGlyphImage> on a hit.

What’s New in 0.2.1

Tips

This is the foundation

OxiText is part of NoFFI — the COOLJAPAN initiative replacing every C/C++/Fortran/-sys dependency in the Rust ecosystem with a clean, memory-safe, Pure-Rust implementation. It pairs with OxiFont for font parsing and discovery, and this release matters most for everything downstream that draws color emoji: oximedia (subtitles and captions), oxiphoton (text on images), OxiUI (every widget, via the oxitext-sdf GPU glyph atlas), oxigdal-symbology (map labels), and oxigaf (PDF/EPUB reflow).

Repository: https://github.com/cool-japan/oxitext

Star the repo if you want color emoji that actually render before you spend an afternoon debugging why they don’t.

Pure Rust typography — sovereign, safe, and FFI-free.

KitaSan at COOLJAPAN OÜ July 30, 2026

↑ Back to all posts