为什么 HTML Canvas getImageData() 不返回与刚刚设置的完全相同的值?

发布于 2024-10-04 16:25:17 字数 894 浏览 2 评论 0原文

当使用 putImageData 将像素写入 HTML Canvas 上下文时,我发现再次获取像素值时并不完全相同。我已经发布了一个显示问题的示例测试页面。归根结底,问题是:

var id = someContext.getImageData(0,0,1,1);
id.data[0]=id.data[3]=64; // 25% red, 25% alpha
id.data[1]=id.data[2]=0;  // No blue or green
someContext.putImageData(id,0,0);
var newData = someContext.getImageData(0,0,1,1);
console.log( newData.data[0] );

在 Chrome v8 上,红色值返回为 63;在 Firefox v3.6、Safari v5 和 IE9 上,红色值返回为 67(均在 Windows 上)。在 OS X 上,Chrome v7、Safari v5 和 Firefox v3.6 也返回为 67。它们都不会以最初设置的 64 值的形式返回!

使用 setTimeout 来延迟设置和重新获取之间没有区别。更改页面背景没有任何区别。在上下文中使用 save()restore() (根据 这篇不太可能的文章)没有什么区别。

When writing pixels to an HTML Canvas context using putImageData I find that the pixel values are not exactly the same when I fetch them again. I have put up a sample test page showing the problem. Boiled down, the problem is:

var id = someContext.getImageData(0,0,1,1);
id.data[0]=id.data[3]=64; // 25% red, 25% alpha
id.data[1]=id.data[2]=0;  // No blue or green
someContext.putImageData(id,0,0);
var newData = someContext.getImageData(0,0,1,1);
console.log( newData.data[0] );

On Chrome v8, the red value comes back as 63; on Firefox v3.6, Safari v5, and IE9 the red value comes back as 67 (all on Windows). On OS X, Chrome v7, Safari v5, and Firefox v3.6 also come back as 67. None of them come back as the 64 value originally set!

Using setTimeout to delay between setting and re-fetching makes no difference. Changing the background of the page makes no difference. Using save() and restore() on the context (per this unlikely article) makes no difference.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不疑不惑不回忆 2024-10-11 16:25:17

ImageData 在 HTML5 中被定义为未预乘,但大多数画布实现都使用预乘后备缓冲区来加速合成等。这意味着当写入数据然后从后备缓冲区读取数据时,它可能会发生变化。

我假设 Chrome v8 从 webkit.org 中获取了 [un]premultiplying 代码的一个有错误的版本(它之前已经被破坏过,尽管我不记得最近发生过任何事情,并且这并不能解释 Windows 唯一的差异)

[编辑:在 Windows 上每晚检查一个 webkit 可能值得吗?由于 imagedata 实现没有任何特定于平台的内容,因此它在所有 webkit 浏览器之间共享,并且可能在基于 MSVC 的构建中被简单地破坏]

ImageData is defined in HTML5 as being unpremultiplied, but most canvas implementations use a premultiplied backing buffer to speed up compositing, etc. This means that when data is written and then read from the backing buffer it can change.

I would assume that Chrome v8 picked up a buggy version of the [un]premultiplying code from webkit.org (It has been broken before, although i don't recall any recent occurances, and that doesn't explain the windows only variance)

[edit: it could be worth checking a webkit nightly on windows? as the imagedata implementation doesn't have anything platform specific it's shared between all webkit browsers and could simply be broken in MSVC based builds]

苦妄 2024-10-11 16:25:17

HTML5 规范鼓励浏览器供应商使用称为 Premultiplied Alpha 的东西。本质上,这意味着像素存储在 32 位整数中,其中每个通道包含一个 8 位颜色值。出于性能原因,浏览器使用预乘 Alpha。它的意思是它根据 alpha 值预乘颜色值。

这是一个例子。您的颜色的 RGB 值为 1286467。现在,为了获得更高的性能,颜色值将预先乘以 alpha 值。因此,如果 Alpha 值为 16,则所有颜色值都将乘以 16/256 (= 0.0625)。在这种情况下,RGB 的结果值变为 844.1875(四舍五入为 4,因为像素颜色值不是浮点数)。

当您完全按照此处所做的操作时,问题就会出现;使用特定的 alpha 值设置颜色数据,然后拉回实际颜色值。当您调用 时,之前的蓝色 4.1875 四舍五入为 4 将变为 64 而不是 67 >getImageData()

这就是为什么您会看到这一切,并且它永远不会改变,除非浏览器引擎中的底层实现更改为使用不受此影响的颜色系统。

HTML5 specification encourages browser vendors to use something that is called Premultiplied Alpha. In essence this means that pixels are stored in 32-bit integers where each channel contains a 8-bit color value. For performance reasons, the Premultiplied Alpha is used by browsers. What it means is that it premultiplies color values based on the alpha value.

Here's an example. You have a color such that the values for RGB are 128, 64, 67. Now, for the sake of higher performance, the color values will be premultiplied by the alpha value. So, in case the alpha value is 16, all the color values will get multiplied by 16/256 (= 0.0625). In this case, the resulting values for RGB become 8, 4, 4.1875 (rounded to 4 because pixel color values are not floats).

The problem shows up when you do exactly what you are doing here; setting color data with a specific alpha value and then pulling back the actual color values. The previous Blue color of 4.1875 that got rounded to 4 will become 64 instead of 67 when you call getImageData().

That is why you are seeing all this and it will never change unless the underlying implementation in a browser engine changes to use a color system that does not suffer from this.

谈情不如逗狗 2024-10-11 16:25:17

对我来说看起来像是一个舍入问题...

64/255 = 0.2509... (rounded down to give 0.25)
0.25 * 255 = 63.75 (rounded down to give 63)
== OR ==
64/255 = 0.2509... (rounded up to give 0.26)
0.26 * 255 = 66.3  (rounded up to give 67)

记住 255 是最大值,而不是 256 ;)

编辑:当然,这不能解释为什么 alpha 通道的行为...

Looks like a rounding issue to me...

64/255 = 0.2509... (rounded down to give 0.25)
0.25 * 255 = 63.75 (rounded down to give 63)
== OR ==
64/255 = 0.2509... (rounded up to give 0.26)
0.26 * 255 = 66.3  (rounded up to give 67)

Remember that 255 is the maximum value, not 256 ;)

EDIT: Of course, this wouldn't explain why the alpha channel is behaving...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文