HTML5:画布上的反色文本颜色

Mui*_*uis 2 html5 canvas

我想在画布上以背景的反色绘制文本(以确保文本是可读的,无论背景颜色如何).我相信oldskool bitblt-ing,这是一个XOR操作.

这该怎么做?

小智 8

更新:大多数较新的浏览器现在支持混合模式"差异",可以实现相同的结果.

context.globalCompositeOperation = "difference";
Run Code Online (Sandbox Code Playgroud)

更新的演示.

老答案:

人们应该认为合成的XOR模式可以做到这一点,但不幸的是,画布'XOR只是对alpha位进行异或.

通过应用以下代码,我们可以收到如下结果:

在此输入图像描述

您可以像这样对画布进行扩展:

CanvasRenderingContext2D.prototype.fillInversedText =
    function(txt, x, y) {
        //code - see below
    }
Run Code Online (Sandbox Code Playgroud)

现在你可以在上下文中调用它作为普通的fillText,但稍有改动:

ctx.fillInversedText(txt, x, y);
Run Code Online (Sandbox Code Playgroud)

为此,我们首先执行以下操作 - 测量文本.目前我们只能计算文本的宽度然后假定高度.这可能会或可能不会很好,因为字体可能非常高等等.幸运的是,这将在未来发生变化,但现在:

var tw = this.measureText(txt).width;
var th = parseInt(ctx.font, '10');
th = (th === 0) ? 10 : th;  //assume default if no font and size is set
Run Code Online (Sandbox Code Playgroud)

接下来我们需要做的是设置一个离屏画布来绘制我们想要反转的文本:

var co = document.createElement('canvas');
co.width = tw;
co.height = th;
Run Code Online (Sandbox Code Playgroud)

然后绘制实际文本.颜色无关紧要,因为我们只对此画布的alpha通道感兴趣:

var octx = co.getContext('2d');
octx.font = this.font;
octx.textBaseline = 'top';
octx.fillText(txt, 0, 0);
Run Code Online (Sandbox Code Playgroud)

然后我们提取我们想要绘制反转文本的区域的像素缓冲区以及现在包含我们文本的屏幕外画布的所有像素:

var ddata = this.getImageData(x, y, tw, th);
var sdata = octx.getImageData(0, 0, tw, th);

var dd = ddata.data;  //cache for increased speed
var ds = sdata.data;
var len = ds.length;
Run Code Online (Sandbox Code Playgroud)

然后我们反转像素的alpha通道大于0的每个像素.

for (var i = 0; i < len; i += 4) {
    if (ds[i + 3] > 0) {
        dd[i] = 255 - dd[i];
        dd[i + 1] = 255 - dd[i + 1];
        dd[i + 2] = 255 - dd[i + 2];
    }
}
Run Code Online (Sandbox Code Playgroud)

最后放回倒像:

this.putImageData(ddata, x, y);
Run Code Online (Sandbox Code Playgroud)

这可能看起来像很多操作,但它的速度非常快.

演示(如果您对闪烁敏感则发出警告)

(迷幻背景只是为了有一些变化,因为小提琴需要外部图像,当我们使用像素操作时,大多数都被CORS阻止).


non*_*ult 1

我删除了旧答案,因为它没有解决问题。截至最近,有一些新的globalCompositeOperation功能可以完成各种伟大的事情。我创建了一个示例来演示如何获取反转文本。如果链接中断,该方法本质上是这样的:

ctx.globalCompositeOperation = "difference";
ctx.fillStyle = "white";
//draw inverted things here
Run Code Online (Sandbox Code Playgroud)

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation