/** Render sample text in every 16-row font, next to the original TP5 bitmap. */ import { readFileSync, writeFileSync } from 'node:fs'; import { FONTS } from '../src/fonts.js'; import { fontFromJSON, renderText } from '../src/codec/bitfont.mjs'; import { parseTd5, frameToPixels } from '../src/codec/td5.mjs'; import { writePNG } from './png.mjs'; const SAMPLE = process.argv[2] ?? 'SCHOOL BUS'; const doc = parseTd5(new Uint8Array(readFileSync(new URL('../../test files/EXPRESS 1.td5', import.meta.url)))); const orig = doc.destinations.find((d) => d.name.startsWith(SAMPLE.slice(0, 10))); const rows = []; if (orig) { const f = orig.frames[0]; rows.push({ label: 'TP5 original (Impact 20)', width: f.width, height: f.height, pixels: frameToPixels(f) }); } for (const [name, j] of Object.entries(FONTS)) { const font = fontFromJSON(j); if (font.height > 16) continue; const bmp = renderText(font, SAMPLE); rows.push({ label: `${name} (${font.cellWidth}x${font.height})`, ...bmp }); } const S = 3, PAD = 6, LABEL = 210, SCREEN = 112; const maxW = Math.max(...rows.map((r) => r.width)); const W = LABEL + maxW * S + PAD * 2; const H = rows.length * (16 * S + PAD) + PAD; const px = new Map(); rows.forEach((r, i) => { const oy = PAD + i * (16 * S + PAD); for (let y = 0; y < r.height; y++) for (let x = 0; x < r.width; x++) if (r.pixels[y * r.width + x]) for (let dy = 0; dy < S; dy++) for (let dx = 0; dx < S; dx++) px.set((oy + y * S + dy) * W + LABEL + x * S + dx, 1); }); writeFileSync(new URL('./fontpreview.png', import.meta.url), writePNG(W, H, (x, y) => { if (px.has(y * W + x)) return [255, 176, 0]; // mark where the 112px screen ends if (x === LABEL + SCREEN * S) return [80, 30, 30]; return [14, 14, 16]; })); console.log(`sample: ${JSON.stringify(SAMPLE)} screen is ${SCREEN}px wide`); for (const r of rows) { const fits = r.width <= SCREEN ? 'fits' : `scrolls (+${r.width - SCREEN}px)`; console.log(` ${r.label.padEnd(26)} ${String(r.width).padStart(3)}px ${fits}`); } console.log('wrote test/fontpreview.png');