2

I'm trying to use alpha blending with the HTML5 canvas. While the colors seem roughly OK to the eye, examining the actual pixel values with context.getImageData() shows discrepancies from the standard Porter-Duff model that seem far too large to be explained by the limitations of 8-bit arithmetic.

Here's the summary:

  1. Read a blank canvas => R=G=B=A=0. This is a bit strange. Since my unpainted canvas shows up as pure white, I would have expected R=G=B=255. Of course, with A=0, the R, G, and B are irrelevant anyway. Nonetheless, I'm not sure how R=G=B=A=0 displays as pure white.

  2. Paint over it with R=200,G=B=0,A=0.75. Read the result as R=201,G=B=0,A=0.75. The A=0.75 seems correct; Porter-Duff want A_final=.75+(.25*0)=.75. The G=B=0 is fine too. But I believe the R should be R=(.75*200)+(0*(.75-1)*0)=150. Clearly 150 != 201. Instead, they seem to have used the equation Final_color=new_color for R, G and B.

  3. Paint over it again with R=100,G=200,B=0,A=0.2. Read the result as R=175,G=50,B=0,A=0.8. Again, the A computations seem correct; .2+(1-.2)*.75=.8. However, Porter-Duff predicts R=(.2*100)+(.75*(1-.2)*201)=(.2*100)+(.6*201)=141. Again, clearly 141 != 175. Green is similarly inconsistent. However, both R and G are explained by the formula Final_color=.25*new_color+.75*old_color -- which unfortunately is not what Porter-Duff blending predicts.

A few other notes:

  • I've presented all alpha values above as being in the range [0,1] for simplicity. Of course, getImageData actually returns them in [0,255].
  • I've checked the spec, and it seems to agree with me as far as what the canvas should do.

  • I've tried both Chrome V37 and IE V11 with essentially the same results.

  • Painting with A=0 works fine, as does painting with A=1.

  • I found a 2011 post that complains of similar issues, but believes it is a browser bug. I have a hard time believing such a blatant bug would still remain three years later -- to appear identically in two different browsers.

Here are the code details for how I did the reading:

pixels=(context.getImageData (10,10,1,1)).data; console.log(pixels);

And the writing:

context.beginPath();
context.arc (10,10, 10, 0, 2*Math.PI);
context.fillStyle = "rgba(200,0,0,.75)";
context.fill ();
Community
  • 1
  • 1
JoelG
  • 129
  • 3

0 Answers0