From 92a173128431f243481131e4afabf7942ce5625e Mon Sep 17 00:00:00 2001 From: Mathis Mensing Date: Fri, 16 Oct 2026 20:01:49 +0000 Subject: [PATCH] renderText: fallback fonts and color glyphs (COLR v0, CBDT) - renderText takes a font or an array of fonts by priority: every character comes from the first font that has a glyph for it, the first font sets the line height. Kerning applies within a font, whole pixel placement follows each glyph's own font's hinting. - src/render/color.ts parses COLR version 0 layers with the first CPAL palette, and CBDT/CBLC bitmaps (index formats 1-5, image formats 17-19) from the strike closest to the size. Fonts with only bitmaps load. - Color glyphs render into a premultiplied RGBA layer over the text: layers through the rasterizer, PNGs decoded and resampled. The text color's alpha applies to them, layers in the text color take its color; outlines go around them too. - Default ignorable code points (joiners, variation selectors, tags) take no room, as HarfBuzz hides them. - Tests with subsets of Noto Color Emoji (OFL) and Twemoji Mozilla (CC-BY 4.0), license notices in tests/fonts. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YJgRK5qpwJEbHPuFv6kgAQ --- CHANGELOG.md | 5 + README.md | 2 +- src/image.ts | 66 +++++-- src/render/color.ts | 148 +++++++++++++++ src/render/font.ts | 6 +- src/render/text.ts | 231 +++++++++++++++++++----- tests/font.js | 33 ++++ tests/fonts/CC-BY-Twemoji.md | 8 + tests/fonts/OFL-NotoColorEmoji.md | 93 ++++++++++ tests/fonts/noto color emoji subset.ttf | Bin 0 -> 73368 bytes tests/fonts/twemoji mozilla subset.ttf | Bin 0 -> 15408 bytes tests/targets/emoji-cbdt.png | Bin 0 -> 12143 bytes tests/targets/emoji-colr.png | Bin 0 -> 6438 bytes 13 files changed, 531 insertions(+), 61 deletions(-) create mode 100644 src/render/color.ts create mode 100644 tests/fonts/CC-BY-Twemoji.md create mode 100644 tests/fonts/OFL-NotoColorEmoji.md create mode 100644 tests/fonts/noto color emoji subset.ttf create mode 100644 tests/fonts/twemoji mozilla subset.ttf create mode 100644 tests/targets/emoji-cbdt.png create mode 100644 tests/targets/emoji-colr.png diff --git a/CHANGELOG.md b/CHANGELOG.md index d9339478..7ea6d2d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ Rotating a 1920×1080 photo by 30° takes 51 instead of 119 ms (61 instead of 114 ms with alpha). Opaque pixels stay within 1 of 3.2.1 (0.5-2% of the values differ), what shows of translucent ones (also the faded edges) within about 2.5 steps. `fast: false` keeps the precise sampling. +- `Image.renderText` takes several fonts by priority (`[text, emoji]`): every character comes from the first font that + has it, the first font sets the line height. Color glyphs keep their colors: COLR version 0 layers with CPAL + palettes (e.g. Twemoji) and CBDT/CBLC bitmaps (e.g. Noto Color Emoji, which now loads at all, it has no outlines). + Invisible characters like joiners and variation selectors take no room, as in browsers. Emoji sequences (skin tones, + flags, families) still show as their parts. ### Performance diff --git a/README.md b/README.md index e4a49e27..df8c0d4e 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ deno add jsr:@matmen/imagescript # Deno (npm:imagescript works too) - [Rendering SVGs](https://imagescript.matmen.dev/classes/Image.html#rendersvg) (shapes, paths, gradients, strokes, clip paths, masks, CSS; no text, images or filters) - [Rendering vector fonts](https://imagescript.matmen.dev/classes/Image.html#rendertext) (TrueType and OpenType, with kerning, - outlines and TrueType hinting) + outlines, TrueType hinting, fallback fonts and color emoji) - [Resizing](https://imagescript.matmen.dev/classes/Image.html#resize) (bilinear, bicubic, area averaging and nearest neighbor) - Image manipulation functions ([crop](https://imagescript.matmen.dev/classes/Image.html#crop) , [rotate](https://imagescript.matmen.dev/classes/Image.html#rotate) diff --git a/src/image.ts b/src/image.ts index e294fb17..aa403ddc 100644 --- a/src/image.ts +++ b/src/image.ts @@ -2031,17 +2031,21 @@ export class Image { /** * Creates a new image containing the rendered text. - * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use + * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use, or several by priority: every character + * comes from the first font that has it (e.g. `[text, emoji]`), the first one sets the line height. Color + * glyphs (COLR version 0 layers and CBDT bitmaps, as in emoji fonts) keep their colors * @param size Font size in pixels (per em) * @param text Text to render * @param options Color, layout and style, see {@link TextOptions}; the image grows by the outline width on every * side * @return The rendered text */ - static renderText(font: BinaryData, size: number, text: string, options?: TextOptions): Promise; + static renderText(font: BinaryData | BinaryData[], size: number, text: string, options?: TextOptions): Promise; /** * Creates a new image containing the rendered text. - * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use + * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use, or several by priority: every character + * comes from the first font that has it (e.g. `[text, emoji]`), the first one sets the line height. Color + * glyphs (COLR version 0 layers and CBDT bitmaps, as in emoji fonts) keep their colors * @param size Font size in pixels (per em) * @param text Text to render * @param [color=0xffffffff] Text color to use @@ -2049,15 +2053,18 @@ export class Image { * @param style Outline, see {@link TextStyle}; the image grows by the outline width on every side * @return The rendered text */ - static renderText(font: BinaryData, size: number, text: string, color?: Color, layout?: TextLayout, style?: TextStyle): Promise; - static async renderText(font: BinaryData, size: number, text: string, colorOrOptions: Color | TextOptions = 0xffffffff, layoutArgument?: TextLayout, styleArgument: TextStyle = {}): Promise { + static renderText(font: BinaryData | BinaryData[], size: number, text: string, color?: Color, layout?: TextLayout, style?: TextStyle): Promise; + static async renderText(font: BinaryData | BinaryData[], size: number, text: string, colorOrOptions: Color | TextOptions = 0xffffffff, layoutArgument?: TextLayout, styleArgument: TextStyle = {}): Promise { const options: TextOptions = isOptions(colorOrOptions) ? colorOrOptions : { ...styleArgument, color: colorOrOptions, layout: layoutArgument }; const { color = 0xffffffff, layout = new TextLayout(), strokeWidth = 0, strokeColor = 0x000000ff, hinting = true } = options; if (isNaN(strokeWidth) || strokeWidth < 0) throw new RangeError('Invalid stroke width'); + const fonts = Array.isArray(font) ? font : [font]; + if (!fonts.length) throw new RangeError('No font given'); - const rendered = textRenderer.render(view(font), size, text, layout, hinting); const [r, g, b, a] = Image.colorToRGBA(color); + // color glyph layers in the text color take it without its alpha, which applies to the whole color glyph + const rendered = await textRenderer.render(fonts.map(view), size, text, layout, hinting, (r << 24 | g << 16 | b << 8 | 255) >>> 0); // the outline needs room around the glyphs const pad = Math.ceil(strokeWidth); @@ -2065,11 +2072,17 @@ export class Image { const coverage = new Uint8Array(width * height); for (let y = 0; y < rendered.height; y++) coverage.set(rendered.coverage.subarray(y * rendered.width, (y + 1) * rendered.width), (y + pad) * width + pad); + let colored: Uint8ClampedArray | null = null; + if (rendered.color) { + colored = new Uint8ClampedArray(width * height * 4); + for (let y = 0; y < rendered.height; y++) + colored.set(rendered.color.subarray(y * rendered.width * 4, (y + 1) * rendered.width * 4), ((y + pad) * width + pad) * 4); + } const image = new Image(width, height); const bitmap = image.bitmap; - if (!strokeWidth) { + if (!strokeWidth && !colored) { for (let i = 0; i < coverage.length; i++) { if (!coverage[i]) continue; bitmap[i * 4] = r; @@ -2080,19 +2093,38 @@ export class Image { return image; } - const stroke = outline(coverage, width, height, strokeWidth); + // the outline goes around the color glyphs as well + let shape = coverage; + if (colored && strokeWidth) { + shape = coverage.slice(); + for (let i = 0; i < shape.length; i++) shape[i] = Math.max(shape[i], colored[i * 4 + 3]); + } + const stroke = strokeWidth ? outline(shape, width, height, strokeWidth) : null; const [sr, sg, sb, sa] = Image.colorToRGBA(strokeColor); - // the glyphs drawn over their outline + // color glyphs over the text (premultiplied, with the text's alpha), both over their outline for (let i = 0; i < coverage.length; i++) { - const af = coverage[i] / 255 * a / 255, as = stroke[i] * sa / 255; - const ao = af + as * (1 - af); - if (ao <= 0) continue; - - bitmap[i * 4] = (r * af + sr * as * (1 - af)) / ao; - bitmap[i * 4 + 1] = (g * af + sg * as * (1 - af)) / ao; - bitmap[i * 4 + 2] = (b * af + sb * as * (1 - af)) / ao; - bitmap[i * 4 + 3] = ao * 255; + let af = coverage[i] / 255 * a / 255, pr = r * af, pg = g * af, pb = b * af; + if (colored && colored[i * 4 + 3]) { + const ca = colored[i * 4 + 3] / 255 * a / 255, keep = 1 - ca, f = a / 255; + pr = colored[i * 4] * f + pr * keep; + pg = colored[i * 4 + 1] * f + pg * keep; + pb = colored[i * 4 + 2] * f + pb * keep; + af = ca + af * keep; + } + if (stroke) { + const as = stroke[i] * sa / 255 * (1 - af); + pr += sr * as; + pg += sg * as; + pb += sb * as; + af += as; + } + if (af <= 0) continue; + + bitmap[i * 4] = pr / af; + bitmap[i * 4 + 1] = pg / af; + bitmap[i * 4 + 2] = pb / af; + bitmap[i * 4 + 3] = af * 255; } return image; diff --git a/src/render/color.ts b/src/render/color.ts new file mode 100644 index 00000000..24208358 --- /dev/null +++ b/src/render/color.ts @@ -0,0 +1,148 @@ +// color glyphs: layers of outlines with palette colors (COLR version 0 with CPAL), and bitmaps (CBDT/CBLC, PNG) + +import { Font } from './font.ts'; + +/** an outline glyph drawn in a color, RGBA as 0xrrggbbaa (null: the text color) */ +export interface ColorLayer { + glyph: number; + color: number | null; +} + +/** a glyph's PNG and where it goes, in pixels of its strike */ +export interface BitmapGlyph { + png: Uint8Array; + /** pixels per em of the strike */ + ppem: number; + /** size of the bitmap */ + width: number; + height: number; + /** offset of the bitmap's left edge from the pen position */ + left: number; + /** offset of the bitmap's top edge above the baseline */ + top: number; +} + +/** + * The layers of the font's color glyphs (COLR version 0 records, with the colors of the first CPAL palette), null if the + * font has none. The lookup returns null for glyphs without layers + */ +export function parseColorLayers(font: Font): ((glyph: number) => ColorLayer[] | null) | null { + const colr = font.tables.COLR?.offset, cpal = font.tables.CPAL?.offset; + if (colr === undefined || cpal === undefined) return null; + + const baseCount = font.u16(colr + 2), bases = colr + font.u32(colr + 4), layers = colr + font.u32(colr + 8); + if (!baseCount) return null; + + // the first palette + const entries = font.u16(cpal + 2), records = cpal + font.u32(cpal + 8), first = font.u16(cpal + 12); + const color = (index: number): number | null => { + if (index === 0xffff || index >= entries) return null; + const o = records + (first + index) * 4; // blue, green, red, alpha + return (font.u8(o + 2) << 24 | font.u8(o + 1) << 16 | font.u8(o) << 8 | font.u8(o + 3)) >>> 0; + }; + + const cache = new Map(); + return glyph => { + let result = cache.get(glyph); + if (result !== undefined) return result; + result = null; + // base glyph records are sorted by glyph + for (let lo = 0, hi = baseCount - 1; lo <= hi;) { + const mid = lo + hi >> 1, record = bases + mid * 6, id = font.u16(record); + if (id < glyph) lo = mid + 1; + else if (id > glyph) hi = mid - 1; + else { + const start = font.u16(record + 2), count = font.u16(record + 4); + result = []; + for (let i = 0; i < count; i++) { + const layer = layers + (start + i) * 4; + result.push({ glyph: font.u16(layer), color: color(font.u16(layer + 2)) }); + } + break; + } + } + cache.set(glyph, result); + return result; + }; +} + +/** + * The font's bitmap glyphs (CBDT/CBLC with PNG images) from the strike closest to `size` (the smallest at least as + * large, else the largest), null if the font has none. The lookup returns null for glyphs without a bitmap + */ +export function parseBitmaps(font: Font, size: number): ((glyph: number) => BitmapGlyph | null) | null { + const cblc = font.tables.CBLC?.offset, cbdt = font.tables.CBDT?.offset; + if (cblc === undefined || cbdt === undefined) return null; + + const sizes = font.u32(cblc + 4); + let strike = -1, strikePpem = 0; + for (let i = 0; i < sizes; i++) { + const ppem = font.u8(cblc + 8 + i * 48 + 45); + const better = strike < 0 || (strikePpem < size ? ppem > strikePpem : ppem >= size && ppem < strikePpem); + if (better) { strike = cblc + 8 + i * 48; strikePpem = ppem; } + } + if (strike < 0) return null; + + const array = cblc + font.u32(strike), subtables = font.u32(strike + 8); + + // where a glyph's data starts in CBDT, its image format, and its metrics if the index holds them (image format 19) + const locate = (glyph: number): { offset: number, format: number, metrics: number } | null => { + for (let i = 0; i < subtables; i++) { + const entry = array + i * 8, firstGlyph = font.u16(entry), lastGlyph = font.u16(entry + 2); + if (glyph < firstGlyph || glyph > lastGlyph) continue; + + const header = array + font.u32(entry + 4); + const indexFormat = font.u16(header), format = font.u16(header + 2), data = cbdt + font.u32(header + 4), k = glyph - firstGlyph; + switch (indexFormat) { + case 1: { + const start = font.u32(header + 8 + k * 4), end = font.u32(header + 12 + k * 4); + return end > start ? { offset: data + start, format, metrics: -1 } : null; + } + case 2: return { offset: data + k * font.u32(header + 8), format, metrics: header + 12 }; + case 3: { + const start = font.u16(header + 8 + k * 2), end = font.u16(header + 10 + k * 2); + return end > start ? { offset: data + start, format, metrics: -1 } : null; + } + case 4: { + const count = font.u32(header + 8); + for (let j = 0; j < count; j++) { + const pair = header + 12 + j * 4; + if (font.u16(pair) === glyph) return { offset: data + font.u16(pair + 2), format, metrics: -1 }; + } + return null; + } + case 5: { + const size = font.u32(header + 8), count = font.u32(header + 20); + for (let j = 0; j < count; j++) + if (font.u16(header + 24 + j * 2) === glyph) return { offset: data + j * size, format, metrics: header + 12 }; + return null; + } + default: return null; + } + } + return null; + }; + + const cache = new Map(); + return glyph => { + let result = cache.get(glyph); + if (result !== undefined) return result; + result = null; + + const location = locate(glyph); + if (location) { + const { format } = location; + let o = location.offset, metrics = location.metrics; + // small metrics (height, width, bearingX, bearingY, advance) and big ones start alike + if (format === 17) { metrics = o; o += 5; } + else if (format === 18) { metrics = o; o += 8; } + if ((format === 17 || format === 18 || format === 19) && metrics >= 0) { + const length = font.u32(o); + result = { png: font.data.subarray(o + 4, o + 4 + length), ppem: strikePpem, width: font.u8(metrics + 1), height: font.u8(metrics), left: font.i8(metrics + 2), top: font.i8(metrics + 3) }; + } + } + + cache.set(glyph, result); + return result; + }; +} diff --git a/src/render/font.ts b/src/render/font.ts index 292116d5..617b0d63 100644 --- a/src/render/font.ts +++ b/src/render/font.ts @@ -42,7 +42,8 @@ export class Font { lineGap: number; numberOfHMetrics: number; numGlyphs: number; - outlines: 'glyf' | 'cff'; + /** where the glyph outlines come from ('none' for fonts with only bitmap glyphs) */ + outlines: 'glyf' | 'cff' | 'none'; cff: CFF | null = null; cmap: (codepoint: number) => number; outlineCache: Map; @@ -89,6 +90,7 @@ export class Font { this.outlines = 'cff'; this.cff = parseCFF(this, this.tables['CFF '].offset); } else if (this.tables.CFF2) throw new Error('Font: CFF2 outlines are not supported'); + else if (this.tables.CBDT && this.tables.CBLC) this.outlines = 'none'; else throw new Error('Font: no supported glyph outlines'); this.cmap = parseCmap(this, this.tables.cmap.offset); @@ -221,7 +223,7 @@ export class Font { if (glyph >= this.numGlyphs) glyph = 0; let path = this.outlineCache.get(glyph); if (!path) { - path = this.outlines === 'glyf' ? this.glyfOutline(glyph, 0) : this.cffOutline(glyph); + path = this.outlines === 'glyf' ? this.glyfOutline(glyph, 0) : this.outlines === 'cff' ? this.cffOutline(glyph) : []; this.outlineCache.set(glyph, path); } return path; diff --git a/src/render/text.ts b/src/render/text.ts index dd5de462..2fa60e8b 100644 --- a/src/render/text.ts +++ b/src/render/text.ts @@ -5,6 +5,9 @@ import { Font, PathCommand } from './font.ts'; import { Hinter } from './hinting.ts'; +import { ColorLayer, BitmapGlyph, parseColorLayers, parseBitmaps } from './color.ts'; +import { decode as decodePNG } from '../codecs/png.ts'; +import { resample, TRIANGLE } from '../util/resample.ts'; export interface Layout { maxWidth: number; @@ -25,8 +28,28 @@ export interface GlyphBitmap { top: number; } +/** a color glyph's premultiplied RGBA pixels, placed like a {@link GlyphBitmap} */ +interface ColorBitmap { + data: Uint8ClampedArray; + width: number; + height: number; + left: number; + top: number; +} + +/** a font with what's derived from it for one size */ +interface SizedFont { + font: Font; + /** pixels per font unit */ + scale: number; + hinter: Hinter | null; + layers: ((glyph: number) => ColorLayer[] | null) | null; + bitmaps: ((glyph: number) => BitmapGlyph | null) | null; +} + interface Glyph { index: number; + font: SizedFont; /** outline and its scale to pixels (1 for hinted outlines, which are in pixels) */ path: PathCommand[]; scale: number; @@ -36,6 +59,10 @@ interface Glyph { ink: { left: number, right: number } | null; /** bitmaps per subpixel offset */ bitmaps: Array; + /** the layers or the bitmap of color glyphs */ + color: { layers: ColorLayer[] } | { bitmap: BitmapGlyph } | null; + /** color bitmaps per subpixel offset (bitmap glyphs only have the one for offset 0) */ + colors: Array; } interface Line { @@ -63,53 +90,76 @@ function loadFont(data: Uint8Array): Font { /** * Lays out and rasterizes text - * Lines start at ceil(ascender) and advance by ceil(ascender - descender + lineGap); glyphs are placed with - * subpixel precision using their advance widths and the font's kerning; the canvas spans from the origin to the - * furthest glyph edge - * @param {Uint8Array} data TrueType/OpenType font - * @param {number} size font size in pixels per em - * @param {string} text - * @param {Layout} layout + * Lines start at ceil(ascender) and advance by ceil(ascender - descender + lineGap) of the first font; every character + * comes from the first font that has a glyph for it. Glyphs are placed with subpixel precision using their advance + * widths and the font's kerning; the canvas spans from the origin to the furthest glyph edge + * @param fonts TrueType/OpenType fonts, by priority + * @param size font size in pixels per em + * @param text + * @param layout * @param hinting Whether to run TrueType fonts' hinting instructions, the glyphs of hinted fonts are then placed on * whole pixels (fonts without instructions render as without hinting) - * @return {{width: number, height: number, coverage: Uint8Array}} + * @param foreground RGBA color (0xrrggbbaa) of color glyph layers drawn in the text color + * @return the coverage of the outline glyphs, and the premultiplied RGBA pixels of color glyphs (null without any) */ -export function render(data: Uint8Array, size: number, text: string, layout: Layout, hinting = false): { width: number, height: number, coverage: Uint8Array } { - const font = loadFont(data); - const scale = size / font.unitsPerEm; - let hinter: Hinter | null = null; - if (hinting && font.outlines === 'glyf') { - hinter = hinters.get(font) ?? null; - if (!hinter) hinters.set(font, hinter = new Hinter(font)); - if (!hinter.hasInstructions) hinter = null; - } - // whole pixel placement only makes sense for hinted outlines - hinting = hinter !== null; - const ascent = Math.ceil(font.ascender * scale); - const lineHeight = Math.ceil((font.ascender - font.descender + font.lineGap) * scale); +export async function render(fonts: Uint8Array[], size: number, text: string, layout: Layout, hinting = false, foreground = 0xffffffff): Promise<{ width: number, height: number, coverage: Uint8Array, color: Uint8ClampedArray | null }> { + const sized: SizedFont[] = fonts.map(data => { + const font = loadFont(data); + let hinter: Hinter | null = null; + if (hinting && font.outlines === 'glyf') { + hinter = hinters.get(font) ?? null; + if (!hinter) hinters.set(font, hinter = new Hinter(font)); + if (!hinter.hasInstructions) hinter = null; + } + return { font, scale: size / font.unitsPerEm, hinter, layers: parseColorLayers(font), bitmaps: parseBitmaps(font, size) }; + }); + const primary = sized[0]; + const ascent = Math.ceil(primary.font.ascender * primary.scale); + const lineHeight = Math.ceil((primary.font.ascender - primary.font.descender + primary.font.lineGap) * primary.scale); const glyphs = new Map(); - const glyph = (codepoint: number): Glyph => { - let g = glyphs.get(codepoint); - if (!g) { - const index = font.glyphIndex(codepoint); + const make = (f: SizedFont, index: number): Glyph => { + const { font, scale, hinter } = f; + const bitmap = f.bitmaps?.(index) ?? null, layers = bitmap ? null : f.layers?.(index) ?? null; + // hinted glyphs go on whole pixels (it only makes sense for hinted outlines) + const advance = font.advance(index) * scale; + const g: Glyph = { index, font: f, path: [], scale, advance: hinter ? Math.round(advance) : advance, ink: null, bitmaps: [], color: null, colors: [] }; + if (bitmap) { + const s = size / bitmap.ppem; + g.color = { bitmap }; + g.ink = { left: bitmap.left * s, right: (bitmap.left + bitmap.width) * s }; + } else if (layers) { + g.color = { layers }; + g.ink = inkExtent(layers.flatMap(layer => font.outline(layer.glyph)), scale); + } else { const hinted = hinter && hinter.glyph(index, size); - if (hinted) g = { index, path: hinted.path, scale: 1, advance: hinted.advance, ink: inkExtent(hinted.path, 1), bitmaps: [] }; + if (hinted) Object.assign(g, { path: hinted.path, scale: 1, advance: hinted.advance, ink: inkExtent(hinted.path, 1) }); else { - const path = font.outline(index); - const advance = font.advance(index) * scale; - g = { index, path, scale, advance: hinting ? Math.round(advance) : advance, ink: inkExtent(path, scale), bitmaps: [] }; + g.path = font.outline(index); + g.ink = inkExtent(g.path, scale); } + } + return g; + }; + const glyph = (codepoint: number): Glyph => { + let g = glyphs.get(codepoint); + if (!g) { + const f = sized.find(f => f.font.glyphIndex(codepoint)); + // invisible characters (joiners, variation selectors, ...) show nothing even where fonts have glyphs for + // them (as HarfBuzz does), characters no font has show the first one's .notdef + if (defaultIgnorable(codepoint)) g = { index: 0, font: primary, path: [], scale: primary.scale, advance: 0, ink: null, bitmaps: [], color: null, colors: [] }; + else g = f ? make(f, f.font.glyphIndex(codepoint)) : make(primary, 0); glyphs.set(codepoint, g); } return g; }; - const kerning = font.kerning; - const kern = kerning ? (left: Glyph, right: Glyph): number => { - const k = kerning(left.index, right.index) * scale; - return hinting ? Math.round(k) : k; - } : () => 0; + const kern = (left: Glyph, right: Glyph): number => { + const kerning = left.font === right.font && left.font.font.kerning; + if (!kerning) return 0; + const k = kerning(left.index, right.index) * left.font.scale; + return left.font.hinter ? Math.round(k) : k; + }; const lines = wrap(text, layout, glyph, kern); // lines that fit into maxHeight, chosen by the vertical alignment @@ -126,28 +176,106 @@ export function render(data: Uint8Array, size: number, text: string, layout: Lay const width = Math.ceil(Math.max(0, ...visible.map(line => line.extent))); const height = visible.length * lineHeight; const coverage = new Uint8Array(width * height); + let color: Uint8ClampedArray | null = null; - visible.forEach((line, n) => { + for (const [n, line] of visible.entries()) { let offset = layout.horizontalAlign === 'right' ? width - line.extent : layout.horizontalAlign === 'center' ? (width - line.extent) / 2 : 0; - if (hinting) offset = Math.round(offset); + if (primary.hinter) offset = Math.round(offset); const baseline = ascent + n * lineHeight; for (const { x, glyph: g } of line.glyphs) { if (!g.ink) continue; - // whole pixels plus the closest subpixel offset - const position = Math.round((offset + x) * SUBPIXELS) / SUBPIXELS; + // whole pixels plus the closest subpixel offset (none for hinted glyphs) + const position = g.font.hinter ? Math.round(offset + x) : Math.round((offset + x) * SUBPIXELS) / SUBPIXELS; const pixel = Math.floor(position); - const subpixel = Math.round((position - pixel) * SUBPIXELS); + let subpixel = Math.round((position - pixel) * SUBPIXELS); + + if (g.color) { + // bitmaps are placed on whole pixels + if ('bitmap' in g.color) subpixel = 0; + if (g.colors[subpixel] === undefined) g.colors[subpixel] = 'bitmap' in g.color + ? await scaledBitmap(g.color.bitmap, size / g.color.bitmap.ppem) + : layeredGlyph(g, g.color.layers, subpixel / SUBPIXELS, foreground); + const bitmap = g.colors[subpixel]; + if (bitmap) blitColor(color ??= new Uint8ClampedArray(width * height * 4), width, height, bitmap, pixel + bitmap.left, baseline - bitmap.top); + continue; + } if (g.bitmaps[subpixel] === undefined) g.bitmaps[subpixel] = rasterizeGlyph(g.path, g.scale, subpixel / SUBPIXELS); const bitmap = g.bitmaps[subpixel]; if (bitmap) blit(coverage, width, height, bitmap, pixel + bitmap.left, baseline - bitmap.top); } - }); + } + + return { width, height, coverage, color }; +} + +// default ignorable code points (Unicode's DerivedCoreProperties), which render as nothing +const IGNORABLE = [0xad, 0xad, 0x34f, 0x34f, 0x61c, 0x61c, 0x115f, 0x1160, 0x17b4, 0x17b5, 0x180b, 0x180f, 0x200b, 0x200f, 0x202a, 0x202e, + 0x2060, 0x206f, 0x3164, 0x3164, 0xfe00, 0xfe0f, 0xfeff, 0xfeff, 0xffa0, 0xffa0, 0xfff0, 0xfff8, 0x1bca0, 0x1bca3, 0x1d173, 0x1d17a, + 0xe0000, 0xe0fff]; +function defaultIgnorable(codepoint: number): boolean { + for (let i = 0; i < IGNORABLE.length; i += 2) if (codepoint >= IGNORABLE[i] && codepoint <= IGNORABLE[i + 1]) return true; + return false; +} + +// a bitmap glyph's PNG decoded and scaled from its strike to the font size, premultiplied +async function scaledBitmap(glyph: BitmapGlyph, scale: number): Promise { + let decoded; + try { + decoded = await decodePNG(glyph.png); + } catch { + return null; + } + const width = Math.max(1, Math.round(decoded.width * scale)), height = Math.max(1, Math.round(decoded.height * scale)); + const data = new Uint8ClampedArray(width * height * 4); + resample(new Uint8ClampedArray(decoded.pixels.buffer, decoded.pixels.byteOffset, decoded.pixels.length), decoded.width, decoded.height, width, height, TRIANGLE, data, true); + premultiply(data); + return { data, width, height, left: Math.round(glyph.left * scale), top: Math.round(glyph.top * scale) }; +} + +// a layered color glyph: every layer's outline filled with its color over the ones below, premultiplied +function layeredGlyph(g: Glyph, layers: ColorLayer[], offset: number, foreground: number): ColorBitmap | null { + const rasters = layers.map(layer => ({ bitmap: rasterizeGlyph(g.font.font.outline(layer.glyph), g.scale, offset), color: layer.color ?? foreground })); + let left = Infinity, top = -Infinity, right = -Infinity, bottom = Infinity; + for (const { bitmap } of rasters) if (bitmap) { + left = Math.min(left, bitmap.left); + top = Math.max(top, bitmap.top); + right = Math.max(right, bitmap.left + bitmap.width); + bottom = Math.min(bottom, bitmap.top - bitmap.height); + } + if (right <= left) return null; + + const width = right - left, height = top - bottom; + const data = new Uint8ClampedArray(width * height * 4); + for (const { bitmap, color } of rasters) { + if (!bitmap) continue; + const r = color >>> 24, gr = color >> 16 & 255, b = color >> 8 & 255, a = color & 255; + for (let y = 0; y < bitmap.height; y++) + for (let x = 0; x < bitmap.width; x++) { + const coverage = bitmap.data[y * bitmap.width + x]; + if (!coverage) continue; + const o = ((top - bitmap.top + y) * width + bitmap.left - left + x) * 4; + // source over, premultiplied + const sa = coverage * a / 255, keep = 1 - sa / 255; + data[o] = r * sa / 255 + data[o] * keep; + data[o + 1] = gr * sa / 255 + data[o + 1] * keep; + data[o + 2] = b * sa / 255 + data[o + 2] * keep; + data[o + 3] = sa + data[o + 3] * keep; + } + } + return { data, width, height, left, top }; +} - return { width, height, coverage }; +function premultiply(rgba: Uint8ClampedArray): void { + for (let i = 0; i < rgba.length; i += 4) { + const a = rgba[i + 3] / 255; + rgba[i] *= a; + rgba[i + 1] *= a; + rgba[i + 2] *= a; + } } // horizontal ink extent of an outline in pixels @@ -244,6 +372,27 @@ function blit(target: Uint8Array, width: number, height: number, bitmap: GlyphBi } } +// draws premultiplied RGBA over the target (premultiplied RGBA as well) +function blitColor(target: Uint8ClampedArray, width: number, height: number, bitmap: ColorBitmap, x0: number, y0: number): void { + for (let y = 0; y < bitmap.height; y++) { + const ty = y0 + y; + if (ty < 0 || ty >= height) continue; + + for (let x = 0; x < bitmap.width; x++) { + const tx = x0 + x; + if (tx < 0 || tx >= width) continue; + + const s = (y * bitmap.width + x) * 4, sa = bitmap.data[s + 3]; + if (!sa) continue; + const o = (ty * width + tx) * 4, keep = 1 - sa / 255; + target[o] = bitmap.data[s] + target[o] * keep; + target[o + 1] = bitmap.data[s + 1] + target[o + 1] * keep; + target[o + 2] = bitmap.data[s + 2] + target[o + 2] * keep; + target[o + 3] = sa + target[o + 3] * keep; + } + } +} + /** * Rasterizes a glyph outline into an 8-bit coverage bitmap * @param {Array} path outline in font units (y up) diff --git a/tests/font.js b/tests/font.js index 99882bab..eb37a289 100644 --- a/tests/font.js +++ b/tests/font.js @@ -3,6 +3,8 @@ https://www.1001fonts.com/carbon-font.html https://www.1001fonts.com/ethnocentric-font.html https://github.com/adobe-fonts/source-sans (SIL OFL, see OFL-SourceSans3.md) + https://github.com/googlefonts/noto-emoji (subset, SIL OFL, see OFL-NotoColorEmoji.md) + https://github.com/mozilla/twemoji-colr (subset, CC-BY 4.0, see CC-BY-Twemoji.md) */ const fs = require('fs').promises; @@ -151,4 +153,35 @@ const panic = message => { if (!Buffer.from(on.bitmap).equals(Buffer.from(off.bitmap))) panic(`hinting: ${file} has no instructions and should render unchanged`); } } + + { + // color glyphs from fallback fonts: CBDT bitmaps (Noto Color Emoji) and COLR layers (Twemoji) + const sans = await fs.readFile('./tests/fonts/sourcesans3 regular.otf'); + for (const [file, target] of [['noto color emoji subset.ttf', 'emoji-cbdt'], ['twemoji mozilla subset.ttf', 'emoji-colr']]) { + const emoji = await fs.readFile(`./tests/fonts/${file}`); + const image = await Image.renderText([sans, emoji], 48, 'Hi 😀🔥 👍', {color: 0x000000ff}); + const encoded = await image.encode(1, {creationTime: 0, software: ''}); + if (process.env.OVERWRITE_TEST) + await fs.writeFile(`./tests/targets/${target}.png`, encoded); + if (!await samePixels(await fs.readFile(`./tests/targets/${target}.png`), encoded)) panic(`${target} doesn't match`); + + // black text, so colored pixels come from the emoji + let colored = 0; + for (let i = 0; i < image.bitmap.length; i += 4) if (image.bitmap[i + 3] > 128 && image.bitmap[i] > 128) colored++; + if (colored < 500) panic(`${file}: emoji should keep their colors`); + + // joiners and variation selectors take no room, even where the font has glyphs for them + const plain = await Image.renderText([sans, emoji], 48, '😀😀'), joined = await Image.renderText([sans, emoji], 48, '😀\u200d\ufe0f😀'); + if (plain.width !== joined.width) panic(`${file}: invisible characters should take no room (${plain.width} vs ${joined.width})`); + + // characters the emoji font doesn't have come from the next font (the first one still sets the line height) + const fallback = await Image.renderText([emoji, sans], 48, 'Hi'), direct = await Image.renderText(sans, 48, 'Hi'); + const ink = image => image.bitmap.reduce((sum, v, i) => (i & 3) === 3 ? sum + v : sum, 0); + if (fallback.width !== direct.width || ink(fallback) !== ink(direct)) panic(`${file}: missing characters should come from the next font`); + } + + // fonts with only bitmap glyphs render on their own + const bitmapOnly = await Image.renderText(await fs.readFile('./tests/fonts/noto color emoji subset.ttf'), 32, '🔥'); + if (bitmapOnly.width < 20) panic('bitmap font should render on its own'); + } })(); diff --git a/tests/fonts/CC-BY-Twemoji.md b/tests/fonts/CC-BY-Twemoji.md new file mode 100644 index 00000000..ea04150b --- /dev/null +++ b/tests/fonts/CC-BY-Twemoji.md @@ -0,0 +1,8 @@ +`twemoji mozilla subset.ttf` is a subset (a few emoji, made with fontTools' pyftsubset) of Twemoji Mozilla 0.7.0 +(https://github.com/mozilla/twemoji-colr). + +The emoji graphics are from Twemoji (https://github.com/twitter/twemoji), Copyright 2019 Twitter, Inc and other +contributors, licensed under CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/). + +The font's build code is Copyright 2016-2018 Mozilla Foundation, licensed under the Apache License, Version 2.0 +(https://www.apache.org/licenses/LICENSE-2.0). diff --git a/tests/fonts/OFL-NotoColorEmoji.md b/tests/fonts/OFL-NotoColorEmoji.md new file mode 100644 index 00000000..6e0c92ae --- /dev/null +++ b/tests/fonts/OFL-NotoColorEmoji.md @@ -0,0 +1,93 @@ +Copyright 2022 Google Inc. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/tests/fonts/noto color emoji subset.ttf b/tests/fonts/noto color emoji subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1a4563cbe1d136907ef8b7a17a4f3e94c599715e GIT binary patch literal 73368 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

xpNxpddvY@+4@IAx*kq`z#=~BonAgoQ{p;?H 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 abpc96{Qe!N;qRQ$%z)hQYx0i;?tcL&xb?08 literal 0 HcmV?d00001 diff --git a/tests/fonts/twemoji mozilla subset.ttf b/tests/fonts/twemoji mozilla subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a1fd84be378f3490d73bab40f1620ec5d2b353f7 GIT binary patch literal 15408 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 literal 0 HcmV?d00001 diff --git a/tests/targets/emoji-cbdt.png b/tests/targets/emoji-cbdt.png new file mode 100644 index 0000000000000000000000000000000000000000..caa07d02d7496020c5db417e5ef365918c0cc67d GIT binary patch literal 12143 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 literal 0 HcmV?d00001 diff --git a/tests/targets/emoji-colr.png b/tests/targets/emoji-colr.png new file mode 100644 index 0000000000000000000000000000000000000000..edc21c7d430773e288bcbef494ad9b7b39e8755b GIT binary patch literal 6438 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