Never thought I'd come up with something new on Stack Overflow but here we are. Should this already have a solution then please feel free to point me towards it. I'm working on this interactive desktop environment modelled after the Amiga Workbench and of course I would incorporate a recreation of the Topaz font. Here is the thing though. Text and signs like hivens, commas and points display correctly when drawn through the Canvas API but signs like the copyright sign or backslash for instance do not.
Amiga Workbench screen where the copyright sign doesn't display correctly
I figured that the font I'm using maybe doesn't include the copyright sign but that struck me as weird. Why go through the trouble of making a font and then omit a couple of signs right? If you open the font with Font Forge you clearly see that it's there along with a range of exotic other stuff.
Font Forge showing set of signs saved in font data
Looking at the set also rules out that there is a mixup between unicodes. I used the same font in Gimp where I made a visual mockup/prototype and the copyright sign is displayed with no problem. That rules out any keyboard layout shenanigans right?
Screenshot of Gimp where the copyright sign displays correctly
The only thing left is my code which I guess is unproblematic. Here is how I weave in the font and draw text:
const amigaFont = new FontFace(
'Topaz A1200',
'url(./media/font/Topaz_a1200_v1.0.ttf)'
);
amigaFont.load().then(function (font) {
document.fonts.add(amigaFont);
});
// between here is code that essentially waits for all media to have
// loaded like images and including the font before it is
// used to draw text, setting up the canvas etc...
const splashScreenText = [
'AMIGA ROM Operating System and Libraries',
'Copyright © 1985-1992 Commodore-Amiga, Inc.',
'All Rights Reserved.',
'1>'
];
let fontSize = Math.round(amigaDOSwindow.bottom * (24 / 356));
ctx.font = fontSize.toString() + 'px Topaz A1200';
textCursor.x = amigaDOSinput.left;
textCursor.y = amigaDOSinput.top + fontSize;
for (let index = 0; index < splashScreenText.length; index++) {
ctx.fillText(splashScreenText[index], textCursor.x, textCursor.y);
textCursor.y += fontSize;
}
Edit: I was asked to share runnable code that reproduces the issue:
const mediaCount = 1;
const mediaArray = [];
const mediaManager = setInterval(checkArray, 15);
function checkArray() {
switch (true) {
case mediaArray.length == mediaCount:
clearInterval(mediaManager);
initCanvas();
break;
default:
break;
}
}
const amigaFont = new FontFace(
'Topaz A1200',
'url(https://cdn.jsdelivr.net/gh/rewtnull/amigafonts@master/ttf/Topaz_a1200_v1.0.ttf)'
);
amigaFont.load().then(function (font) {
document.fonts.add(amigaFont);
mediaArray.push(amigaFont);
});
const splashScreenText = [
'AMIGA ROM Operating System and Libraries',
'Copyright © 1985-1992 Commodore-Amiga, Inc.',
'All Rights Reserved.',
'1>'
];
const textCursor = {
x: 0,
y: 0,
};
function initCanvas() {
let canvas = document.createElement('canvas');
canvas.id = 'canvas';
document.body.appendChild(canvas);
processCanvas();
}
function processCanvas() {
let canvas = document.getElementById('canvas');
canvas.width = 320;
canvas.height = 180;
drawText();
}
function drawText() {
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let fontSize = 32;
ctx.font = fontSize.toString() + 'px Topaz A1200';
textCursor.x = 0;
textCursor.y = 0 + fontSize;
for (let i = 0; i < splashScreenText.length; i++) {
ctx.fillText(splashScreenText[i], textCursor.x, textCursor.y);
textCursor.y += fontSize;
}
}
<canvas id="canvas"></canvas>
But somehow here it works...
Is there something (I clearly don't know) about fonts and the Canvas API that may lead to this behaviour?
Given that you get a replacement character (U+FFFD) this means that it's not a font issue, otherwise you'd fallback to another font, not on the replacement glyph. Instead, it means that your issue is an encoding one.
I don't know what charset your document is declared with, and I don't know what charset your html file has been encoded with, but clearly there is a mismatch.
If you do both save your html page as UTF-8 and add a <meta charset="utf-8">
in the head of your document, your glyph will render correctly, as it does in your snippet.