为什么用图像绘制的 canvas 的颜色与图像本身的颜色略有不同?

Why is a canvas drawn with an image a slightly different color than the image itself?

我正在将图像绘制到 HTML canvas 并从中获取图像数据以查找特定像素的颜色。该图像是一张地图,其中每个国家/地区的颜色都不同。我想将 .getImageData() 返回的颜色与我手工制作的颜色列表进行交叉引用,以查找任何给定像素所在的国家/地区。

我的问题是,我绘制到 canvas 的图像和绘制的图像颜色略有不同。

这是绘制到canvas的原图:

这是我将 canvas 下载为 PNG 时得到的图片:

两者看起来几乎一模一样,但如果你下载它们并在照片编辑软件中打开它们,你会发现它们不是。比如上图的灰色海洋是73,73,73,255,下图的灰色海洋是71,71,71,255。

我仍然可以完成确定像素所在国家/地区的目标,但是我需要根据我下载的图片绘制到 canvas 后创建一个新列表。

这似乎是一个非常奇怪的问题。

如果有人想知道,我的代码如下所示:

HTML:

<img scr="active_map.png" class="active" id="activeImage">
<canvas id="activeCanvas" width="439px" height="245px">Your Browser Doesn't Support HTML5 Canvases... Sorry :( </canvas>

JS:

var activeCanvas = document.getElementById('activeCanvas')
var activeContext = activeCanvas.getContext("2d");
var activeImage = document.getElementById('activeImage')
activeContext.drawImage(activeImage,0,0);
var activePixelData = activeContext.getImageData(0,0,439,245)["data"];

此外,我正在使用 Firefox 31 Ubuntu

-感谢您的帮助

浏览器可以自由预乘 alpha 和(如 GameAlchemist 所说)进行伽玛校正。

结果是不同的浏览器显示的颜色值可能与 FF 显示的颜色值略有不同。

可能的解决方法:

  • 假设浏览器会混淆你的确切颜色,所以你的测试在国家原始颜色周围的一小部分颜色上成功。

  • 向客户端发送一个预先计算好的数组,表示 canvas 上的每个像素,其中包含哪个国家/地区位于该像素下。该数组类似于 .getImageData,但每个像素只有 1 个值——该值将是该像素的国家/地区代码。

  • 计算勾画出每个国家的路径。然后你可以使用 context.isPointInPath 来测试鼠标是否在一个国家内。 DougX 做得很好:http://dougx.net/map/

  • 如果内存是一个问题,您可以重构上面的预先计算的数组以使用树结构中的对象。例如:

    1. 将您的地图划分为 9x4 网格(或 4x2 或其他)。
    2. 为每个网格单元格创建一个对象数组。对象可能如下所示:{ x0:297, x1:353 y0:91, y1:94 country:55 } 其中 countryCodes[55]='China'。此示例对象表示 (353-297)*(94-91)==224 像素。
    3. 鼠标点击时,计算鼠标所在的网格单元格,然后扫描数组,直到找到确切的鼠标 [x,y]。您可以从网格数组中省略所有海洋坐标,因此如果您的测试没有找到匹配项,您可以假设鼠标在海洋中。

正如@GameAlchemist 所提到的,您正在使用的 PNG 存在潜在的伽马校正问题,即 RGB 值不会被一致地解释。

Henri Sivonen 的 The Sad Story of PNG Gamma “Correction” 提供了非常透彻的分析。简而言之:

In order to compensate for the different gammas, the display gamma of the system an image was authored on and the display gamma of the system where the image is being displayed both need to be known to the piece of software displaying the image. The PNG format provides a means for storing the (reciprocal of) display gamma of the authoring system to the image file. It is up to the program writing the file to store the native display gamma of the image, and then it is up to program displaying the file to compensate.

他建议使用 Pngcrush 删除可能导致这种不一致的颜色配置文件。我已经确认他的技术 (pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile.png outfile.png) 确实有效。这是您修改后的图片:

您会发现它小了 6KB。我已经确认这在 Firefox 之前和之后都按预期工作(从 RGB 值 71、71、71 到值 73、73、73)。