I am reading RGBA data from a png file in JavaScript. To do this I draw the image on a canvas and use .getImageData. The data differs from what I expect:
The third pixel's RGBA in JS is: [9, 0, 0, 54] (tested in chrome and firefox) but it should be [12, 0, 0, 54] (at least it is what gimp and python pillow claim).
My guesses what could be wrong
drawImage does some compositing (setting ctx.globalCompositeOperation to copy does not make any difference)
there is some color mangament going on at load time of the image
Example Code
Select the test image
check console output
解决方案
1) Compositing
The more draw operations applied the more rounding errors will occur over time. However, with an initial draw this won't matter.
copy mode doesn't affect it as you discovered. This is just ignoring the existing background data. source-over do use alpha value of background, but as there is none initially it will have the same effect.
The main problem with this though is that there is general problems with alpha and rounding errors due to pre-multiplied alpha values which needs to be converted internally.
2) Color management
Browsers do support various levels of color management. This includes the following data from the PNG file:
sRGB chunk stating how the PNG conforms to the sRGB standard (relative, absolute etc.)
iCCP chunk which contains an ICC profile including gamma, that if the browser support ICC and also this version of ICC (typical versions are version 2 and 4).
If no sRGB or iCCP profile are found, it will look for gAMA chunk which contains a number representing the gamma.
When these data are applied it will alter the original bitmap. Gamma will not affect the lowest nor the highest values, but the mid-range will have a noticeable change. Values that are still altered will be altered due to color management and conversion errors (1.).
For example, even if the file does not have a gamma chunk (or a "file gamma"), which is the case for your test file, or its value is 1, a display gamma will still be applied (except in IE). For windows this would be 2.2 and for Mac typically 1.8.
And this happens before the image is returned to be used in the code with canvas.
Alternatively I would suggest taking a look at my
Test using pngtoy
This will show the raw unaltered bitmap value.
var out = document.querySelector("output"),
png = new PngToy();
png.fetch("https://i.imgur.com/oX1kom7.png").then(
function() {png.decode().then(show)}
);
function show(bmp) {
var data = bmp.bitmap;
out.innerHTML += data[8] + "," + data[9] + "," + data[10] + "," + data[11];
}
Loading external scripts (pngtoy.min.js + Promise polyfill for IE...)