4

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

这该怎么做?

4

2 回答 2

8

更新:大多数较新的浏览器现在都支持混合模式“差异”,可以达到相同的效果

context.globalCompositeOperation = "difference";

更新了演示

老答案:

人们应该认为合成的 XOR 模式会做到这一点,但不幸的是,画布的 XOR 仅对 alpha 位进行 XOR。

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

在此处输入图像描述

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

CanvasRenderingContext2D.prototype.fillInversedText =
    function(txt, x, y) {
        //code - see below
    }

现在您可以在上下文中将其作为普通的 fillText 调用,但需要稍作改动:

ctx.fillInversedText(txt, x, y);

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

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

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

var co = document.createElement('canvas');
co.width = tw;
co.height = th;

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

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

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

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;

然后我们反转每个像素的 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];
    }
}

最后放回倒置的图像:

this.putImageData(ddata, x, y);

这可能看起来像很多操作,但它进行得非常快。

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

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

于 2013-06-07T20:37:36.643 回答
1

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

ctx.globalCompositeOperation = "difference";
ctx.fillStyle = "white";
//draw inverted things here

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

于 2013-06-16T00:19:07.813 回答