如何在javascript画布中使用后退字体

i2loujxw  于 2023-01-29  发布在  Java
关注(0)|答案(2)|浏览(107)

我想知道我是否可以检测我的实际字体是否支持字符串的所有字符。
例如,我们可以看到不支持的字符用Times New Roman填充,而正常文本用选定的字体填充:

但我想首先把整个文本与相同的字体,如果一个字符是不支持的,太切换字体与Arial。
你知道我该怎么做吗?

dced5bon

dced5bon1#

ctx.font使用与CSS's font shorthand相同的语法(忽略行高参数),因此您可以使用与CSS相同的方式指定备用字体,即在末尾添加多个字体系列值:

ctx.font = "10px 'your font', Arial";
3pvhb19x

3pvhb19x2#

要同时进行回退,您可以使用measureText,通过检查每个字母与回退字体的度量来检测是否有字母正在使用回退字体。
请注意,理想情况下,您应该检查每个字素,而不是每个代码点。JavaScript的for-of循环迭代字符串的代码点,但有grapheme-splitter这样的库可以帮助迭代字素。
这个解决方案的性能可能不是很好,但是对于短文本来说应该是不错的,特别是如果你缓存结果的话。注意如果你缓存它,你应该确保你的字体在缓存之前被加载,以避免在字体加载时缓存失效,最好是在测试之前,因为在这种情况下它必须回退。

/* const splitter = new GraphemeSplitter(); */
const font = "JinxedWizards";
const fallbackFont = "Arial, sans-serif";

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

function usesFallback(text) {
    for (const grapheme of /*splitter.iterateGraphemes*/(text)) {
        ctx.font = "20px " + font + ", " + fallbackFont;
        const metrics = ctx.measureText(grapheme);
        ctx.font = "20px " + fallbackFont;
        const fallbackMetrics = ctx.measureText(grapheme);
        if (
            metrics.width === fallbackMetrics.width &&
            metrics.actualBoundingBoxAscent === fallbackMetrics.actualBoundingBoxAscent &&
            metrics.actualBoundingBoxDescent === fallbackMetrics.actualBoundingBoxDescent &&
            metrics.actualBoundingBoxLeft === fallbackMetrics.actualBoundingBoxLeft &&
            metrics.actualBoundingBoxRight === fallbackMetrics.actualBoundingBoxRight
            /* fontBoundingBoxAscent seems to give different results somehow... don't ask me why!
            metrics.fontBoundingBoxAscent === fallbackMetrics.fontBoundingBoxAscent &&
            metrics.fontBoundingBoxDescent === fallbackMetrics.fontBoundingBoxDescent */
        ) {
            //console.log("fallback detected for", grapheme, metrics, fallbackMetrics);
            return true;
        } else {
            //console.log("differs for", grapheme, metrics, fallbackMetrics);
        }
    }
    return false;
}

console.log("usesFallback('testing')", usesFallback('testing'));
console.log("usesFallback('testing œ')", usesFallback('testing œ'));

// manually verify that we can display the font
document.body.append(canvas);
ctx.font = "20px " + font + ", " + fallbackFont;
ctx.fillText("testing œ", 50, 50);

相关问题