Please see this example: http://codepen.io/anon/pen/QNGzBP
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// set pixel at 0,0 to rgba(2, 0, 255, 0.2)
const imageData = ctx.getImageData(0, 0, 1, 1)
imageData.data[0] = 2
imageData.data[1] = 0
imageData.data[2] = 255
imageData.data[3] = 0.2 * 255 // 0.2 opacity
ctx.putImageData(imageData, 0, 0, 0, 0, 1, 1)
console.log('Setting pixel 0,0 to', {
r: imageData.data[0],
g: imageData.data[1],
b: imageData.data[2],
a: imageData.data[3] / 255
})
// retrieve pixel at 0,0
const newImageData = ctx.getImageData(0, 0, 1, 1)
console.log('Fetching pixel at 0,0', {
r: newImageData.data[0],
g: newImageData.data[1],
b: newImageData.data[2],
a: newImageData.data[3] / 255
})
The above code modifies a single pixel on the canvas, and then retrieves it, while console logging the process. The canvas seems to mutate the RGB data when the alpha is lower than 1.
It seems to occur both in Chrome and Firefox. Is this simply a browser bug? I'm producing a PNG out of the canvas, and require the colors to be 100% accurate. Is there any workaround?
Edit:
http://codepen.io/anon/pen/ZWLbKx
More tests to show how the alpha mutates the rgb values.
Very sorry to disappoint, but the HTML5 canvas has been ratified as "lossy": it uses alpha-channel premultiplication.
From https://www.w3.org/TR/2dcontext/#dom-context-2d-getimagedata (see 2nd "Note:" box):
Due to the lossy nature of converting to and from premultiplied alpha color values, pixels that have just been set using
putImageData()
might be returned to an equivalentgetImageData()
as different values.
Recommended reading: How can I stop the alpha-premultiplication with canvas imageData?
Also relevant: Why function returns wrong color in canvas?
Seems vaguely similar but might be regarding a totally different domain: Invalid blending results across all browsers with HTML5 canvas
...There are lots of JavaScript PNG encoders/decoders. Unfortunately that's where it's at, as of 2017.
FWIW, I've had a go at bumping the r/g/b/a values up and down to try and make the canvas spit out the values I actually want. 5 minutes of experimenting shows that it "hops" over the specific pixel value you want depending on what the alpha is set to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With