1

I have a canvas object from which i want to get the color of a position with canvas.getImageData. When i paint a gradient on it and try to get the color from point (0,0) chrome behaves as expected and returns the color value 255,255,255 whereas IE returns 254,253,253.

I have here a plunker which shows what i mean :

http://plnkr.co/edit/BWSn2J2N2A6poaH4WR6a?p=preview

You can just execute this in IE and in Chrome and you'll see the difference. I use the IE v11 and the Chrome v40.

Maybe the error is during my creation of the canvas.

var RepaintGradient = function(gradient)
{           
    _gradientContext.fillStyle = 'rgb(255,0,0)';
    _gradientContext.fillRect(0,0,width,height);

    var gradientWTT = _gradientContext.createLinearGradient(0, 0, width, 0);
    gradientWTT.addColorStop(0, "white");
    gradientWTT.addColorStop(1, gradient);
    _gradientContext.fillStyle = gradientWTT;
    _gradientContext.fillRect(0, 0, width, height);

    var gradientBTT = _gradientContext.createLinearGradient(0, width, 0, 0);
    gradientBTT.addColorStop(0, "black");
    gradientBTT.addColorStop(1, "transparent");
    _gradientContext.fillStyle = gradientBTT;
    _gradientContext.fillRect(0, 0, width, height);
    var color = _gradientContext.getImageData(0, 0, 1, 1).data;
    alert(color[0]+' '+color[1]+' '+color[2]);
};

Is this a normal behavior and IE and Chrome have this difference or is it something that i missed during the creation of the canvas ?

Bongo
  • 2,933
  • 5
  • 36
  • 67

2 Answers2

1

This is due to rounding errors during blending and composition when sub-pixeling is used - different browsers gain different result based on their approach (IE and FireFox gives the same result, webkit browsers a different result).

It's not much we can do with the inner working, but we can adjust for sub-pixeling so it won't happen by simply translating the canvas half pixel.

Add this line to the top of the gradient function:

  _gradientContext.setTransform(1,0,0,1, 0.5,0.5); // offset 0.5 pixel

and it should work

The reason being that pixels are initially rendered from the pixel's center, meaning 0.5 of the pixel is interpolated both ways. Translating 0.5 pixel will match the center to the pixel grid.

Update (from comments):

Another approach using coordinates to calculate color value (HSL) instead of picking a pixel (this approach will also allow you to set a point in the picker based on input values):

  • marvellous, thank you for this explanation and the solution. It seems to work in the example provided and i hope is will work in the projekt i am implementing – Bongo Feb 25 '15 at 23:36
  • 1
    @Bongo no problem! just be aware of that if you use transforms other places you will need a save/restore in the function (or better, rebuild the transforms each you need them) - otherwise, this will reset them. –  Feb 25 '15 at 23:39
  • Interestin...I was aware of the gradient differences between browsers, but I've never tried to reconcile the difference. Does this offset technique work if the angle of the linear gradient is changed? – markE Feb 25 '15 at 23:49
  • 1
    @markE I haven't tried but as the main issue in this case is sub-pixeling there is a good chance it should work. Though, the alpha channel would be another factor (and possibly gamma) so it need to be tested... –  Feb 25 '15 at 23:54
  • @KenFyrstenberg it works fine for the 0,0 position but if you try it with position 0,254 it seems that the color is interpreted not so right. I guess this has to do with the alpha channel, can you suggest any good reading material on that ? – Bongo Feb 28 '15 at 12:53
  • @Bongo ok.. just replace the setTransform(1,0,0,1,0.5,0.5) to setTransform(1,0,0,1, **0**, 0.5). Here is also a version which pre-multiplies the alpha channel in case it's non-opaque: http://plnkr.co/edit/K7Ymf0uXQCUMcDurDNrY?p=preview –  Mar 01 '15 at 11:01
  • 1
    @Bongo another approach using coordinates to calculate color value (HSL) instead of picking a pixel (this approach will also allow you to set a point in the picker based on input values): https://stackoverflow.com/questions/16835070/create-gradient-for-color-selection-with-html5-canvas-all-possible-rgb-colors/16841734#16841734 –  Mar 01 '15 at 11:05
  • 1
    @KenFyrstenberg I changed yesterday everything to coordinates. So your second approach was my favourit :) – Bongo Mar 01 '15 at 12:18
  • 1
    @Bongo great to hear :) - I updated the answer to include this. –  Mar 02 '15 at 21:02
1

It's normal...

Different browsers are allowed to impliment slightly different renderings of canvas gradients.

Even one image will be rendered slightly differently on each browser.

markE
  • 102,905
  • 11
  • 164
  • 176