El siguiente código pretende establecer el color de fondo del lienzo en rgba(16,0,0,0.1) , con un resultado esperado de [16,0,0,26] , asumiendo que un valor alfa de 0.1 es equivalente a un byte ImageData de 26:
var canvas = document.createElement('canvas'); var ctx = canvas.getContext("2d"); ctx.fillStyle = "rgba(16, 0, 0, 0.1)"; ctx.fillRect(0, 0, 50, 50); var output = ctx.getImageData(0, 0, 1, 1).data; console.log(output.toString(16)); Sin embargo, en lugar de [16,0,0,26] , obtenemos [20,0,0,26] . De alguna manera, el valor de un color ha cambiado inexplicablemente. Si los valores RGBA se almacenan correctamente, esto no debería ocurrir, ¿verdad?
Considere este segundo ejemplo, donde establecemos un valor de píxel directamente:
var canvas = document.createElement('canvas'); var ctx = canvas.getContext("2d"); var imgData = ctx.createImageData(50, 50); imgData.data[0] = 16; imgData.data[1] = 0; imgData.data[2] = 0; imgData.data[3] = 26; ctx.putImageData(imgData, 0, 0); var output = imgData.data; console.log(output.slice(0,4).toString()); Ahora recupera correctamente [16,0,0,26] . Sin embargo, si en su lugar output = ctx.getImageData(0, 0, 1, 1).data , nuevamente obtenemos [20,0,0,26] . Esto sugiere que getImageData está haciendo algo mal, corrompiendo nuestros valores de color.
Entonces, ¿por qué 20? Parece estar directamente relacionado con el canal alfa. A medida que disminuye la opacidad, los valores RGB parecen volverse menos precisos de lo que deberían, casi como si el color se estuviera convirtiendo a RGB y luego de nuevo a RGBA. De hecho, esto puede no estar lejos de la verdad, ya que la causa parece estar relacionada con las matemáticas de composición alfa redondeada:
// Divide alpha value var A = 26 / 255; // 0.10196078431372549 var C = 16 * A; // 1.6313725490196078 C = Math.round(C); // rounding should not occur C = C / A; // 19.615384615384617 C = Math.round(C); // rounding should not occur Aquí hay un código de simulación que muestra que este tipo de conversión redondeada representa en gran medida lo que está haciendo getImageData .
Entonces, ¿por qué ocurre esto tanto en Firefox como en Chrome? ¿Es este un error que ha pasado desapercibido durante años, o es un comportamiento muy extraño pero intencional? Si este es un comportamiento intencional, ¿por qué es así y cómo se puede solucionar?