I'm trying to duotone an image and plaster it onto a canvas.
Works in desktop browsers:
Fails in mobile browsers:
Workable demo on JSFiddle, this example works in Chrome but fails in Android's default browser.
The code is:
<style>
body {
background-color: gray;
}
</style>
<canvas id="mycanvas" width="64" height="64"></canvas>
<script>
var image = new Image();
image.src = 'image.png';
image.onload = function () { //once the image finishes loading
var context = document.getElementById("mycanvas").getContext("2d");
context.drawImage(image, 0, 0);
var imageData = context.getImageData(0, 0, 64, 64);
var pixels = imageData.data;
var numPixels = pixels.length;
for (var i = 0; i < numPixels; i++) { //for every pixel in the image
var index = i * 4;
var average = (pixels[index] + pixels[index + 1] + pixels[index + 2]) / 3;
pixels[index] = average + 255; //red is increased
pixels[index + 1] = average; //green
pixels[index + 2] = average; //blue
//pixels[index + 3] = pixels[index + 3]; //no changes to alpha
}
context.clearRect(0, 0, 64, 64); //clear the image
context.putImageData(imageData, 0, 0); //places the modified image instead
}
</script>
The summary is:
The smiley face looks like this (block-quoted so you can tell it's transparent):
However, in comparison with the chrome and android browser,
The background of the android drawing is reddish while the chrome drawing is completely transparent.
So...
Note: I already tried if (pixels[index + 3] == 0) continue;
, and I'm aware of this, but it won't work for images with varying opacity.
Ok, I have a result
.
First of all look at your loop:
for (var i = 0; i < numPixels; i++) { //for every pixel in the image
var index = i * 4;
index
will be more than 3 times bigger than numPixels
. And will get undefined
values. And average will be NaN
. But, then I fixed this - result was the same.
So I tried to use fillStyle
and fillRect
for every pixel. All becomes fine. My code
:
function putImageData(ctx, imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) {
var data = imageData.data;
var height = imageData.height;
var width = imageData.width;
dirtyX = dirtyX || 0;
dirtyY = dirtyY || 0;
dirtyWidth = dirtyWidth !== undefined ? dirtyWidth : width;
dirtyHeight = dirtyHeight !== undefined ? dirtyHeight : height;
var limitBottom = dirtyY + dirtyHeight;
var limitRight = dirtyX + dirtyWidth;
for (var y = dirtyY; y < limitBottom; y++) {
for (var x = dirtyX; x < limitRight; x++) {
var pos = y * width + x;
//adding red increased here
ctx.fillStyle = 'rgba(' + data[pos * 4 + 0] + 255 + ',' + data[pos * 4 + 1] + ',' + data[pos * 4 + 2] + ',' + (data[pos * 4 + 3] / 255) + ')';
ctx.fillRect(x + dx, y + dy, 1, 1);
}
}
};
var image = new Image();
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gcVBAYmslkm5QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABc0lEQVR42u2a3QrDMAiFZ9j7v7K7CpTRVtt4NCEnsJt1BP1y4l8nqvrZebXP5osACIAACIAACIAACIAACIAACIAAqpaIlPXkgpwHiIiqqtw5efa8f7csgIgTVVU5AlwGAELOSAjfLKndOWFBQyohVAHWPR/dCwEBCiDCYDSIViH5p/v87xUZZ8IUkJHGEGpoyLu/QjZomffeE+37xwthFH5aKdwNtQyOyhjT1QGzXosWaYBljMdY72laPUZZDLBq+6jTPO41xRXwGB/1Gw5ECOC6StxSASMQ2o5OQ9Jg5VxviYFI5KxgSQBXzmYNPlLaYctw72jr7ncd2DQx4KkCKud/cACeQNghvAmaCDjhCvBCOFODJX2Pgkp7gben+vR5pAqgL0aip8KI2ABNgyMRGzFiT1FARI+eWTDB3w7P6nhKHVBd5pYDGFVABsCU/wccHblLaxUNEwzACvKHB8EVFoeiBEAABEAABEAABEAABEAAe64fre4tZAeLAbcAAAAASUVORK5CYII=';
image.onload = function () {
var context = document.getElementById("mycanvas").getContext("2d"),
imageData;
context.drawImage(image, 0, 0);
imageData = context.getImageData(0, 0, 64, 64);
putImageData(context, imageData, 0, 0);
}
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