4

I found that getImageData of an HTML canvas seems to return incorrect byte values.

I generated a 1x1 px image with the following Python code:

from PIL import Image
import numpy as np

a = np.array([[[12, 187, 146, 62]]], dtype=np.uint8)
Image.fromarray(a).save('image.png')

I converted the image to base64 to include it in this code snippet:

let image = document.createElement('img');
image.addEventListener('load', () => {
  let canvas = document.createElement('canvas');
  let ctx = canvas.getContext("2d");
  canvas.width = image.width;
  canvas.height = image.height;
  ctx.drawImage(image, 0, 0);
  let data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
  document.body.innerHTML = data;
});

image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGPg2T3JDgADyAGYmiSbAQAAAABJRU5ErkJggg==";

When run in Firefox, it shows 12,189,148,62. In Chromium it shows 12,185,144,62. But the original values are 12,187,146,62.

Can anyone explain this?

Mouagip
  • 5,139
  • 3
  • 37
  • 52
  • For the record: It's possible to read the accurate byte values of an image using [WebGL](https://stackoverflow.com/a/60564905/1796523). – Mouagip Mar 06 '20 at 13:19

1 Answers1

1

Firefox pre-multiplication rounding error

I can confirm that FF (Firefox) does indeed return the pixel value as [12,189,148,62]

When rendering to the canvas pixels are processed according to the value of globalCompositeOperation which defaults to "source-over". The calculation is performed on pre multiplied alpha values for which FF seams to be rounding incorrectly.

Note that turning off alpha canvas.getContext("2d", {alpha: false}) for CanvasRenderingContext2D the resulting pixels are FF [3,46,36,255] and Chrome [3,45,35,255].

Chrome has the correct values as shown in the following snippet.

// correct pre mult alpha 
console.log([12,187,146].map(c => Math.round(c * 62 / 255)) + "");

FF is rounding up for some reason and I would consider this a bug

This rounding error (in FF) is then effecting the result of "source-over" compositing when alpha: true resulting in the higher than expected values.

For more information on compositing W3C Compositing and Blending

Fix?

I can not suggest a fix, only to say that Chrome is rendering the image correctly, while FF is not.

Community
  • 1
  • 1
Blindman67
  • 51,134
  • 11
  • 73
  • 136
  • Thanks for pointing out the issue with premultiplied alpha! If I set the alpha byte to 255, the RGB bytes are reconstructed correctly. Apparently `putImageData` is [considered a lossy operation](https://stackoverflow.com/a/23501676/1796523) if alpha is involved. – Mouagip Feb 05 '20 at 13:17
  • For reference: I have created a bug report for Firefox (https://bugzilla.mozilla.org/show_bug.cgi?id=1613369). – Mouagip Feb 05 '20 at 13:47