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 pngtoy (it's free/MIT) which I created for this type of scenario, to enable developers to get a raw unaltered bitmap from a PNG (just see notes/status as it is currently still in alpha). I supplied a code example below which also reads the third pixel giving 12 for red channel as expected.
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];
}
<script src="https://rawgit.com/epistemex/pngtoy/master/tests/Promise.js"></script>
<script src="https://rawgit.com/epistemex/pngtoy/master/pngtoy.min.js"></script>
<output>Loading external scripts (pngtoy.min.js + Promise polyfill for IE...)<br></output>