Search code examples
javascripthtml5-canvaschromiumgetimagedata

Inconsistent canvas.getimagedata() values returned on Chromium based browsers


Edit: solution is (weirdly) to activate willReadFrequently: true on the canvas, Chromium & getImageData() will return consistent values, see answer below.

I'm currently running a program that pick a pixel from a canvas where an image is previously loaded using canvas.getImageData() , analyse the RGB values from the pixel then run calculations based on blue and red values.

I encountered a weird behavior only on Chrome/Chromium/Edge browsers : the first time and image is loaded, the value returned for a specific pixel is RGB(181,1,1), if i load the exact same image again in the canvas with canvas.drawImage() and pick the exact same pixel multiple times with canvas.getImageData() i now get RGB(181,1,2).

HTML:

<canvas id="canvas" width="500" height="500"></canvas>

JS:

var ctx = document.getElementById("canvas").getContext("2d", {alpha: false,});
    
const IMG = new Image();
IMG.src = "myImage.jpg"

ctx.drawImage(IMG, 0, 0, 500, 500);
console.log("first image draw : " + ctx.getImageData(66, 27, 1, 1).data);

ctx.drawImage(IMG, 0, 0, 500, 500);
console.log("Second image draw : " + ctx.getImageData(66, 27, 1, 1).data);

ctx.drawImage(IMG, 0, 0, 500, 500);
console.log("Third image draw : " + ctx.getImageData(66, 27, 1, 1).data);

ctx.drawImage(IMG, 0, 0, 500, 500);
console.log("Fourth image draw : " + ctx.getImageData(66, 27, 1, 1).data);

ctx.drawImage(IMG, 0, 0, 500, 500);
console.log("fifth image draw : " + ctx.getImageData(66, 27, 1, 1).data);

Result on Chrome :

"first image draw : 181,1,1,255"
"Second image draw : 181,1,1,255"
"Third image draw : 181,1,2,255"
"Fourth image draw : 181,1,2,255"
"fifth image draw : 181,1,2,255"

Result on Firefox :

"first image draw : 181,1,2,255"
"Second image draw : 181,1,2,255"
"Third image draw : 181,1,2,255"
"Fourth image draw : 181,1,2,255"
"fifth image draw : 181,1,2,255"

This behaviour only happen on chromium based browsers, on webkit/firefox i get RGB(181,1,2) no matter what.

I recreated this behaviour on codepen : open it on chrome/firefox and see the difference : https://codepen.io/sh4kman/pen/qBgaNbe

Screenshot comparison

i tried :

  1. Disabling antialiasing (context.imageSmoothingEnabled= false)
  2. Clearing canvas (canvas.clearRect()) before/after every getImageData() call

I'm aware that different browser can have different render/rounding colors for images, but here i have different value on the same browser, always following the same pattern


Solution

  • I cannot give an actual answer to this but experimenting with the willReadFrequently
    attribute of the canvas as mentioned in the warning of the console
    I get different results on Chromium.

    Canvas2D: Multiple readback operations using getImageData are faster with the willReadFrequently attribute set to true. See: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently

    I forked the CodePen link and tried changing the values to undefined (default)
    false and true. All of them behave different from one another.

    undefined

    The default behavior enter image description here

    false

    Consistent behavior with the 3rd value being 1 enter image description here

    true

    Consistent behavior with the 3rd value being 2 enter image description here

    Codepen link: https://codepen.io/Danny2006/pen/vYbXJWR