Files
houseplan-card/scripts/generate-pdf-font.mjs
T
2026-09-07 03:47:57 +03:00

57 lines
2.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { Buffer } from 'node:buffer';
import subsetFont from 'subset-font';
import opentype from 'opentype.js';
const sourcePath = resolve('assets/fonts/Roboto-Regular.ttf');
const outputPath = resolve('src/pdf/pdf-font.generated.ts');
const ranges = [
[0x20, 0x7e], [0xa0, 0x17f], [0x400, 0x52f], [0x2000, 0x206f],
];
const required = new Set(['°', '²', '′', '″', '×', '≈', '€', '₽', '—', '→']);
for (const [start, end] of ranges) {
for (let code = start; code <= end; code++) required.add(String.fromCodePoint(code));
}
const characters = [...required].join('');
const original = readFileSync(sourcePath);
const subset = Buffer.from(await subsetFont(original, characters, { targetFormat: 'truetype' }));
const arrayBuffer = subset.buffer.slice(subset.byteOffset, subset.byteOffset + subset.byteLength);
const font = opentype.parse(arrayBuffer);
const glyphs = {};
const widths = {};
for (const char of characters) {
const code = char.codePointAt(0);
const glyph = font.charToGlyph(char);
if (!code || glyph.index === 0) continue;
glyphs[code] = glyph.index;
widths[glyph.index] = Math.round(glyph.advanceWidth || font.unitsPerEm * 0.5);
}
const generated = `/* Generated by scripts/generate-pdf-font.mjs. DO NOT EDIT. */
export const PDF_FONT_BASE64 = ${JSON.stringify(subset.toString('base64'))};
export const PDF_FONT_UNITS_PER_EM = ${font.unitsPerEm};
export const PDF_FONT_ASCENT = ${Math.round(font.ascender)};
export const PDF_FONT_DESCENT = ${Math.round(font.descender)};
export const PDF_FONT_BBOX = ${JSON.stringify([
Math.round(font.tables.head.xMin), Math.round(font.tables.head.yMin),
Math.round(font.tables.head.xMax), Math.round(font.tables.head.yMax),
])} as const;
export const PDF_FONT_GLYPHS: Readonly<Record<number, number>> = ${JSON.stringify(glyphs)};
export const PDF_FONT_WIDTHS: Readonly<Record<number, number>> = ${JSON.stringify(widths)};
`;
if (process.argv.includes('--check')) {
let current = '';
try { current = readFileSync(outputPath, 'utf8'); } catch {}
if (current !== generated) {
console.error('src/pdf/pdf-font.generated.ts is stale; run npm run pdf-font:generate');
process.exit(1);
}
} else {
writeFileSync(outputPath, generated);
console.log(`Generated ${outputPath} (${subset.length} bytes)`);
}