getImageData() 没有 return 正确的 RGB 值(显示 P3 图像)

getImageData() does not return correct RGB values (Display P3 image)

我编写了一个从图像中提取像素颜色的网站。我通过使用 getImageData on a canvas holding the image. However, I do not manage to get the correct values for this sample image.

来做到这一点

使用Pillow提取时,比如第一个像素颜色(x=0,y=0)它returns(49,97,172,255)为RGBA颜色space.

from PIL import Image 
im = Image.open('image.png').convert('RGBA')
pix = im.load()
print(pix[0, 0])

另外 Java 给了我相同的结果:

BufferedImage bufferedImage = ImageIO.read(new File("image.png"));
        int rawRGB = bufferedImage.getRGB(0, 0);
        Color color = new Color(rawRGB);

但是,当我使用 HTML canvas 时,我通过 getImageData 获得以下值:(27,98,178,255).

let image = new Image();
        const reader = new FileReader();

        image.addEventListener('load', function () {
            let canvas = document.createElement('canvas');
            let ctx = canvas.getContext("2d");
            canvas.width = this.width;
            canvas.height = this.height;
            ctx.drawImage(this, 0, 0);
            let data = ctx.getImageData(0, 0, 1, 1).data;
            document.getElementById('imageData').innerHTML = data;
        });

        image.addEventListener('load', function () {
            let canvas = document.createElement('canvas');
            let gl = canvas.getContext("webgl2");
            gl.activeTexture(gl.TEXTURE0);
            let texture = gl.createTexture();
            gl.bindTexture(gl.TEXTURE_2D, texture);
            const framebuffer = gl.createFramebuffer();
            gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this);
            gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
            let data = new Uint8Array(1 * 1 * 4);
            gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, data);
            document.getElementById('webGl').innerHTML = data;
        });

        reader.addEventListener('load', (event) => {
            image.src = event.target.result;
        });

        var fileToRead = document.getElementById("yourFile");

        fileToRead.addEventListener("change", function (event) {
            var files = fileToRead.files;
            if (files.length) {
                reader.readAsDataURL(event.target.files[0]);
            }
        }, false);
<pre>Expected:  49,97,172,255<br>
ImageData: <span id="imageData"></span><br>
WebGL:     <span id="webGl"></span><br></pre>
<input type="file" id="yourFile" name="file">

我不明白为什么会这样,也不明白浏览器是如何得出这些值的。我试过 Chrome 和 Firefox,它们都显示了相同的错误值。我读过 但我不知道这会对我的结果产生怎样的影响,因为图片没有使用 alpha 通道。如有任何帮助,我们将不胜感激!

这是因为此图像的颜色配置文件设置为 P3,而 webGL 和 2D 上下文的默认颜色-space 是 sRGB,这意味着它们会转换图像的颜色。

现在有个好消息,canvas 2D API 最近扩展到支持 P3 颜色-space,这是最新的 Chrome和 Safari 浏览器(Firefox 和 WebGL 应该会很快跟进)。
要享受此功能,您需要使用 colorSpace: "display-p3" 选项创建您的上下文:

const input = document.querySelector("input");
input.oninput = async(evt) => {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d", {
    colorSpace: "display-p3"
  });
  if (!(ctx.getContextAttributes?.().colorSpace === "display-p3")) {
    console.warn("your browser doesn't support the colorSpace setting");
  }
  const image = new Image();
  image.src = URL.createObjectURL(input.files[0]);
  await image.decode();
  // not resizing the canvas to save memory since we're only interested in top-left pixel
  ctx.drawImage(image, 0, 0);
  const { data } = ctx.getImageData(0, 0, 1, 1);
  console.log(data);
};
<input type="file">