How can I limit the RGB color space of a canvas image to a specific array of colors? F.ex:
var colors = ['#aaffee','#cc44cc','#00cc55','#0000aa'];
var rgb = [230,111,90];
// match rgb with the colors and return the closest match
I need to get the closest match from this array when I loop through the pixels in the canvas image data. Is there a clever function that can do that?
How To limit colors to a specific color palette
You must map each and every original pixel to the nearest palette color.
To do this you actually calculate the distance between the original and palette colors on the colorwheel.
Here is an illustration. The original pixel (orange color) has arrows to each color in our specified palette (assume our palette has 3 specified colors: red, green, blue).
The palette color with the shortest arrow length is substituted for the original pixel.
Since the orange-red arrow is shortest, palette red will be substituted for original orange.
This is the important function that maps original color to palette color:
// use Euclidian distance to find closest color
// send in the rgb of the pixel to be substituted
function mapColorToPalette(red,green,blue){
var color,diffR,diffG,diffB,diffDistance,mappedColor;
var distance=25000;
for(var i=0;i<palette.length;i++){
color=palette[i];
diffR=( color.r - red );
diffG=( color.g - green );
diffB=( color.b - blue );
diffDistance = diffR*diffR + diffG*diffG + diffB*diffB;
if( diffDistance < distance ){
distance=diffDistance;
mappedColor=palette[i];
};
}
return(mappedColor);
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/GWQQH/
Note: you can improve this code using hash tables, tree searches, etc.
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:15px; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvasOriginal=document.getElementById("OriginalCanvas");
var ctx=canvasOriginal.getContext("2d");
var canvasMapped=document.getElementById("MappedCanvas");
var ctxMapped=canvasMapped.getContext("2d");
// draw some off-colored rectangles
ctx.beginPath();
ctx.fillStyle="rgb(140,70,60)"; //red-ish
ctx.rect(10,10,20,20);
ctx.fill();
ctx.beginPath();
ctx.fillStyle="rgb(70,140,60)"; //green-ish
ctx.rect(10,40,20,20);
ctx.fill();
ctx.beginPath();
ctx.fillStyle="rgb(70,60,140)"; //blue-ish
ctx.rect(10,70,20,20);
ctx.fill();
// create an array of palette colors
var palette=[{r:255,g:0,b:0},{r:0,g:255,b:0},{r:0,g:0,b:255}];
// load all pixels into an array
var imageData=ctx.getImageData(0,0,canvasOriginal.width,canvasOriginal.height);
var data=imageData.data;
// rewrite all pixels using only the mapped colors
var mappedColor;
for(var i=0; i<data.length; i+=4) {
mappedColor = mapColorToPalette(data[i], data[i+1], data[i+2]);
if(data[i+3]>10){
data[i] = mappedColor.r;
data[i+1] = mappedColor.g;
data[i+2] = mappedColor.b;
}
}
ctxMapped.putImageData(imageData,0,0);
// use Euclidian distance to find closest color
function mapColorToPalette(red,green,blue){
var color,diffR,diffG,diffB,diffDistance,mappedColor;
var distance=25000;
for(var i=0;i<palette.length;i++){
color=palette[i];
diffR=( color.r - red );
diffG=( color.g - green );
diffB=( color.b - blue );
diffDistance = diffR*diffR + diffG*diffG + diffB*diffB;
if( diffDistance < distance ){
distance=diffDistance;
mappedColor=palette[i];
};
}
return(mappedColor);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="OriginalCanvas" width=60 height=100></canvas>
<canvas id="MappedCanvas" width=60 height=100></canvas>
</body>
</html>
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