mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
57 lines
2.3 KiB
JavaScript
57 lines
2.3 KiB
JavaScript
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)`);
|
||
}
|