I am experimenting with Node Canvas (an implementation of the HTML5 Canvas in NodeJS), trying to write simple text in different fonts.
I can pull system font data fine using the node-system-fonts library's getavailablefonts function which gives me data like
[
{
"path": "/Library/Fonts/AcademyEngravedLet.ttf",
"postscriptName": "AcademyEngravedLetPlain",
"family": "Academy Engraved LET",
"style": "Plain",
"weight": 400,
"width": 5
},
{
"path": "/Library/Fonts/Impact.ttf",
"postscriptName": "Impact",
"family": "Impact",
"style": "Regular",
"weight": 900,
"width": 4
}
]
In the Canvas itself I can specify the font info using a font string, as documented in w3schools.com/TAgs/canvas_font.
import { createCanvas } from "canvas";
import { WIDTH, HEIGHT } from "../config";
const write = (text, font, fontStyle) => {
const canvas = createCanvas(WIDTH, HEIGHT);
const ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.font = `${Math.abs(WIDTH / Math.PI)}px ${font}`;
ctx.fontStyle = fontStyle;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, WIDTH / 2, HEIGHT / 2, WIDTH - 20); // text, x, y, max width
return canvas;
};
But I'm struggling to correctly associate the Font family and style from the font data with what ought to go into the ctx.font property.
In the case of Impact, a font string 200px Impact gives me a system default font rather than the Impact font. But 200px Academy Engraved LET works fine.
Also setting the ctx.fontStyle property to the value of the font's style property doesn't seem to do anything.
Is there documentation somewhere that explains how to map system fonts to the canvas font property?
After a bit of digging around in the actual canvas source I've got this working.
/**
* Convert the font data into a font string.
*
* @param {string} size A font size string (eg 100px or 50%/55% etc)
* @param {object} font The font data, including `{ style, family }`
* @returns {string} The font string
*/
const stringifyFont = (size, { style, family }) =>
[style, size, family].filter(Boolean).map(String).join(" ");
export default stringifyFont;
I also found it helped to register the fonts as that helped me weed out fonts that, for various reasons, just don't work.
import { registerFont } from "canvas";
const registerFonts = (fonts) => {
fonts.forEach(({ path, family, weight, style }) => {
registerFont(path, { family, weight, style });
});
};
export default registerFonts;