Reputation: 177
I have a 2d RTS HTML5 / Javascript game. I use images to display the player's units and buildings. I provide the image and then use a script to replace certain colors in the images with other color, to get different versions of an image with different colors (so the soldier of player 1 has a red sword and the soldier of player 2 has a blue sword and so on...). The problem is, for maybe ~20% of the users this replacing thing doesnt work and they see all units in the same (default) color. Im now wondering why this is. Heres the function i use to replayce the colors:
// returns a image with some colors replaced, specified by search and replace, which are arrays of color arrays ([[255, 255, 255], [...], ...], )
ImageTransformer.replaceColors = function(img, search, replace)
{
var canv = document.createElement('canvas');
canv.height = img.height;
canv.width = img.width
var ctx = canv.getContext('2d');
ctx.drawImage(img, 0, 0);
var imgData = ctx.getImageData(0, 0, canv.width, canv.height);
for(var i = 0; i < imgData.data.length; i += 4)
for(var k = 0; k < search.length; k++)
if(imgData.data[i] == search[k][0] && imgData.data[i + 1] == search[k][1] && imgData.data[i + 2] == search[k][2])
{
imgData.data[i] = replace[k][0];
imgData.data[i + 1] = replace[k][1];
imgData.data[i + 2] = replace[k][2];
}
ctx.putImageData(imgData, 0, 0);
return canv;
}
Upvotes: 0
Views: 98
Reputation: 19294
Browsers may or may not apply a gamma to the image prior to drawing them, the intent is to have more natural colors (...).
I bet this is the Browsers which apply a gama that fool your algorithm.
Rather than test for strict equality, you might use a color distance, and decide of a threshold to decide wether to switch or not :
var imgData = ctx.getImageData(0, 0, canv.width, canv.height);
var data = imgData.data, length = imgData.data.length ;
for(var k = 0; k < search.length; k++) {
var thisCol = search[k];
for(var i = 0; i < length; i += 4) {
var colDist = Math.abs(data[i] - thisCol[0] )
+ Math.abs(data[i+1] - thisCol[1] )
+ Math.abs(data[i+2] - thisCol[2] );
if( colDist < 5 )
{
data[i] = thisCol[0];
data[i + 1] = thisCol[1];
data[i + 2] = thisCol[2];
}
}
}
ctx.putImageData(imgData, 0, 0);
return canv;
(here i used as distance the sum of absolute differences in between r,g,b ; as @MarkE suggest, you can choose others, euclidian being this:
var colDist = sq(data[i] - thisCol[0] )
+ sq(data[i+1] - thisCol[1] )
+ sq(data[i+2] - thisCol[2] );
// notice this is the squared euclidian distance.
// whith function sq(x) { return x*x }
test several pictures / distances, and see what fits.
test several threshold also.
).
Upvotes: 1