UNPKG

autokerning

Version:

autokerning computes suggested kerning values for glyph pairs from TrueType/OpenType fonts by rendering glyph bitmaps, applying a small Gaussian blur, and measuring pixel overlap across horizontal offsets. It can be used programmatically (as an imported E

70 lines (69 loc) 2.51 kB
import { logger } from "./log.js"; let debugCount = 0; /** * Compute pixel overlap using composition logic from Python version * * Intersection rectangle layout: * - Right glyph at x ∈ [0, right.width) * - Left glyph at x ∈ [lOffset, lOffset + left.width) * - Only pixels in both ranges contribute to overlap */ export function overlap(left, right, kern) { const height = left.height; // Calculate offset where left glyph is positioned relative to right const lOffset = -(left.advance + left.bboxOffsetX) + right.bboxOffsetX - kern; // Find intersection range in x-dimension const xStart = Math.max(0, lOffset); const xEnd = Math.min(right.width, lOffset + left.width); const width = Math.max(0, xEnd - xStart); if (debugCount < 3 && width > 0) { logger.debug(`[OVERLAP] pair=${left.char}${right.char}, kern=${kern .toString() .padStart(4)}, lOffset=${lOffset .toFixed(2) .padStart(8)}, [${xStart.toFixed(0)}, ${xEnd.toFixed(0)}) width=${width .toFixed(0) .padStart(4)}`); } if (width <= 0) { return 0; } // Compute intersection by multiplying pixel values let sum = 0; // Use direct typed-array access to avoid ndarray.get overhead inside tight loops const rData = right.bitmap.data; const lData = left.bitmap.data; const rW = right.width; const lW = left.width; const rH = right.height; const lH = left.height; for (let y = 0; y < height; y++) { const rRowOff = y * rW; const lRowOff = y * lW; for (let x = xStart; x < xEnd; x++) { // Right glyph pixel at (x, y) let rVal = 0; if (x >= 0 && x < rW && y < rH) { rVal = rData[rRowOff + x] ?? 0; } // Left glyph pixel at (x - lOffset, y) let lVal = 0; const lx = x - lOffset; const li = Math.floor(lx); if (li >= 0 && li < lW && y < lH) { lVal = lData[lRowOff + li] ?? 0; } // Sum product of squared values sum += lVal * lVal * rVal * rVal; } } if (debugCount < 3 && width > 0) { logger.error(` -> overlap=${sum.toFixed(2).padStart(8)}`); debugCount++; } return sum; } // Export function to set bbox offset (needed during glyph creation) export function setGlyphBboxOffset(glyph, offsetX) { glyph.bboxOffsetX = offsetX; }