有没有办法停止画布数据的Alpha通道的预乘,或者解决方法?

我想生成一个图像(在这种情况下,一些随机的rgba值)并将画布另存为图像。

在第二步中,我想使用imageData将原始图像与生成的图像进行比较,但是由于生成的图像中我的rgba像素的alpha通道的预乘,因此无法正常工作。

The example

function drawImage(ctx) {
    var img = ctx.createImageData(canvas.width,canvas.height);

        for (var i=img.data.length;i-=4;) {
                img.data[i] = Math.floor(Math.random() * 255);
                img.data[i+1] = Math.floor(Math.random() * 255);
                img.data[i+2] = Math.floor(Math.random() * 255);
                img.data[i+3] = Math.floor(Math.random() * 255);
        }

        ctx.putImageData(img, 0, 0);
            // our image data we just set
        console.log(img.data);
            // the image data we just placed onto the canvas
        console.log(ctx.getImageData(0,0,canvas.width, canvas.height).data);
}


在控制台中,您将找到两个console.log输出。第一个在预乘之前,第二个在预乘之后。这两个输出是不同的,有些值相差3或更多。仅当涉及部分透明性时(alpha设置为255以外的任何值),才会发生这种情况。

有没有办法获得相同的输出?关于这个问题有什么想法吗?任何想法如何创建类似的解决方法来解决此问题?

先感谢您!

最佳答案

Bleh,就画布规范而言,这是一个公认的问题。它指出:


  由于在预乘alpha颜色值之间进行转换的有损特性,刚使用putImageData()设置的像素可能会以不同的值返回到等效的getImageData()。


所以这:

var can = document.createElement('canvas');
var ctx = can.getContext('2d');
can.width = 1;
can.height = 1;
var img = ctx.createImageData(1, 1);
img.data[0] = 40;
img.data[1] = 90;
img.data[2] = 200;
var ALPHAVALUE = 5;
img.data[3] = ALPHAVALUE;
console.log(img.data);
ctx.putImageData(img, 0, 0);
console.log(ctx.getImageData(0, 0, 1, 1).data);


输出:

[40, 90, 200, 5]
[51, 102, 204, 5]


在所有浏览器中。

因此,这是有损操作,除非他们更改规范以提供不使用预乘法的选项,否则没有解决方法。 WHATWG邮件列表中早在2008年就对此进行了讨论,他们认为规范不能要求“往返” /放置/获取图像数据的身份。

如果需要“保存”图像数据,则不能使用putImageData保存并保持相同的保真度。通过将全Alpha数据绘制到临时画布并使用较小的globalAlpha重新绘制到主画布的解决方法也不起作用。

所以你很不走运。抱歉。



直到今天(2014年5月12日),这仍然在WHATWG列表中进行讨论:http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-May/296792.html

07-28 11:41