inverse-subset
Version:
A CLI tool to generate inverse subset fonts using a complete font and a subset font.
93 lines (80 loc) • 2.79 kB
JavaScript
const {execSync} = require('child_process');
const fs = require('fs');
const path = require('path');
const fontkit = require('fontkit');
const {Command} = require('commander');
const program = new Command();
// CLI
program
.name('inverse-subset')
.description(
'Generates an inverse subset font from a complete font and a subset font.',
)
.version('1.0.0')
.requiredOption('-c, --complete <path>', 'Path to the complete font file')
.requiredOption('-s, --subset <path>', 'Path to the subset font file')
.option(
'-o, --output <directory>',
'Directory for the inverse subset font',
process.cwd(),
)
.parse(process.argv);
// read command-line arguments
const options = program.opts();
const completeFontPath = options.complete;
const subsetFontPath = options.subset;
const outputDir = options.output;
// validate
if (!fs.existsSync(completeFontPath)) {
console.error(`Error: Complete font file not found at "${completeFontPath}"`);
process.exit(1);
}
if (!fs.existsSync(subsetFontPath)) {
console.error(`Error: Subset font file not found at "${subsetFontPath}"`);
process.exit(1);
}
// Ensure output directory exists
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, {recursive: true});
}
// Generate file name for the inverse subset
const baseName = path.basename(
completeFontPath,
path.extname(completeFontPath),
);
const inverseSubsetFile = path.join(
outputDir,
`${baseName}-inverse-subset.woff2`,
);
// Function to get supported Unicode characters from a font
function getUnicodeCharacters(fontPath) {
const font = fontkit.openSync(fontPath);
return new Set(
font.characterSet.map(
(codePoint) => `U+${codePoint.toString(16).toUpperCase()}`,
),
);
}
const allFontChars = getUnicodeCharacters(completeFontPath);
const subsetFontChars = getUnicodeCharacters(subsetFontPath);
const inverseSubset = [...allFontChars]
.filter((char) => !subsetFontChars.has(char))
.join(',');
// Function to create a subset using glyphhanger
function createSubset(inputFont, outputFont, whitelist) {
const command = `glyphhanger --formats=woff2 --subset="${inputFont}" --whitelist=${whitelist}`;
console.log(`Running: ${command}`);
execSync(command);
// Rename the result cuz glyphhanger always adds `-subset` to the file name
const tempSubsetFile = inputFont.replace(/\.ttf$/, '-subset.woff2');
if (fs.existsSync(tempSubsetFile)) {
fs.renameSync(tempSubsetFile, outputFont);
console.log(`Created: ${outputFont}`);
} else {
console.error(`Subset file not found: ${tempSubsetFile}`);
}
}
// Create the inverse subset
console.log('Creating the inverse subset...');
createSubset(completeFontPath, inverseSubsetFile, inverseSubset);
console.log('Inverse subset generation complete.');