I'm doing a little HTML5 game and, while loading my sprites at the beginning of the map, I do some processing with GetImageData() / looping over all the image / PutImageData().
This works fantastically great on my PC, however, on my cell phones it's horrendously slow.
PC: 5-6 ms
iPhone 4: 300-600 ms
Android HTC Desire S: 2500-3000 ms
I've been doing some VERY basic benchmarking, and both GetImageData and PutImageData run very fast, what's taking long is the looping through the contents.
Now, I obviously expect a slowdown on the phone, but 1000x sounds a bit excessive, and the loading takes about 4 minutes on my HTC, so that's not going to work. Also, everything else in the game works at very reasonable speed (mainly because the screen is ridiculously smaller, but still, it works surprisingly fine for JS on a cell phone)
What I'm doing in this processing is basically "darkening" the sprite to a certain level. I simply loop through all the pixels, and multiply them by a value < 1. That's all.
Since this is too slow... Is there a better way of doing the same thing, using the Canvas functionality, (compositing, opacity, whatever), without looping through all the pixels one by one?
NOTE: This layer has some 100% transparent pixels, and some 100% opaque pixels. Both need to remain either 100% opaque or 100% transparent.
Things I've thought of that wouldn't work:
1) Painting the sprites in a new canvas, with lower opacity. This won't work because i need the sprites to remain opaque, just darker.
2) Painting the sprites, and painting a semi-transparent black rect on top of them. This will make them darker, but it'll also make my transparent pixels not transparent anymore...
Any ideas?
This is the code I'm using, just in case you see something terribly idiotic in it:
function DarkenCanvas(baseImage, ratio) {
var tmpCanvas = document.createElement("canvas");
tmpCanvas.width = baseImage.width;
tmpCanvas.height = baseImage.height;
var ctx = tmpCanvas.getContext("2d");
ctx.drawImage(baseImage, 0, 0);
var pixelData = ctx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height);
var length = pixelData.data.length;
for (var i = 0; i < length; i+= 4) {
pixelData.data[i] = pixelData.data[i] * ratio;
pixelData.data[i + 1] = pixelData.data[i + 1] * ratio;
pixelData.data[i + 2] = pixelData.data[i + 2] * ratio;
}
ctx.putImageData(pixelData, 0, 0);
return tmpCanvas
}
EDIT: This is an example of what i'm trying to do with the image:
Original: http://www.crystalgears.com/isoengine/sprites-ground.png
Darkened: http://www.crystalgears.com/isoengine/sprites-ground_darkened.png
Thanks!
Daniel
globalCompositeOperation
to preserve alpha). – Nocturnal