Javascript 带有文本的HTML画布图像因操作系统而异

Javascript 带有文本的HTML画布图像因操作系统而异,javascript,html,canvas,html5-canvas,Javascript,Html,Canvas,Html5 Canvas,我正在构建一个小的JS类,它包含一个元素,并使用它动态地绘制一些图像。特别是那些图像有背景(填充)和文本 完成此操作后,我想围绕此编写一些单元测试,以确保在给定一些输入的情况下,生成的输出(作为base64字符串)始终是相同的。这意味着,如果我想生成一个带有粉色背景和白色文本的图像,生成的输出总是一个带有白色文本的粉色图像,并且尺寸是相同的。换句话说,base64编码的字符串是相等的 我可以在本地运行这些测试,它们通过了(MacOS),但在我的Jenkins集成作业(在Linux上运行)中失败了

我正在构建一个小的JS类,它包含一个
元素,并使用它动态地绘制一些图像。特别是那些图像有背景(填充)和文本

完成此操作后,我想围绕此编写一些单元测试,以确保在给定一些输入的情况下,生成的输出(作为base64字符串)始终是相同的。这意味着,如果我想生成一个带有粉色背景和白色文本的图像,生成的输出总是一个带有白色文本的粉色图像,并且尺寸是相同的。换句话说,base64编码的字符串是相等的

我可以在本地运行这些测试,它们通过了(MacOS),但在我的Jenkins集成作业(在Linux上运行)中失败了。这是因为图像的字体略有不同。在阅读了很多关于这方面的内容后,我怀疑这是因为不同的操作系统中字体的实现方式不同

请参见以下图片:

预期,在MacOS本地获得:

实际值,在Linux中获得:

您可以看到,我获得的实际图像比预期的高一点(文本下方的底部填充更小)。我目前使用的字体是“44px Arial”

见代码:

实施

单元测试:

作为
expectedTransparentImageWithText
模块的全局变量,它保存我在MacOS中期望并获得的字符串base64值

我必须澄清,对于单元测试,我使用的是在节点上运行的,正如文档所说的,“尽可能地实现该API”(参考Canvas browser API)。我怀疑这就是字体不同的原因。我也得到了,它们之间没有100%的兼容性


有没有什么建议你可以给我更好的单元测试,并考虑字体a好吗?现在我只测试没有文本的图像,所以我可以避免遇到解释过的场景,但当然,这不是最好的做法。

不同的操作系统使用不同的技术绘制字体。例如,MacOs使用亚像素,Windows使用ClearType。这使得使用画布进行指纹识别成为可能。也许像Docker这样的东西可以工作,测试将在相同的环境中运行,而不管主机操作系统是什么。我想Docker不会从主机操作系统继承字体之间的差异。不同的操作系统使用不同的技术来绘制字体。例如,MacOs使用亚像素,Windows使用ClearType。这使得使用画布进行指纹识别成为可能。也许像Docker这样的东西可以工作,测试将在相同的环境中运行,而不管主机操作系统是什么。我想Docker不会从主机操作系统继承字体之间的差异。
 generateImage(backgroundColor, fontColor = "#000000") {
        if (backgroundColor) {
            this.drawBackgroundWithColor(backgroundColor);
        }
        this.drawTexOverBackground("Text to draw", X_POSITION, Y_POSITION, fontColor, "44px Arial");
        return this.getCurrentCanvasAsBase64String();
    }

 drawBackgroundWithColor(backgroundColor){
        if (backgroundColor) {
            const context = this.getCanvasContext();
            context.save();
            context.fillStyle = backgroundColor;
            context.fillRect(0, 0, this.width, this.height);
            context.restore();
        }
    }

drawTexOverBackground(text, x, y, hexColor, font = this.font) {
        const context = this.getCanvasContext();
        context.save();
        context.font = font;
        context.textBaseline = "top";
        context.fillStyle = hexColor;
        context.fillText(text, x, y);
        context.restore();
    }
it('should create a basic pink background with black text', () => {
        const backgroundGenerator = new ImageGenerator();
        const createdBackground = backgroundGenerator.generateImage("#FFC0CB");
        assert.equal(createdBackground, expectedTransparentImageWithText);
    });