Skip to content

Instantly share code, notes, and snippets.

@hapticdata
Last active March 18, 2016 21:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hapticdata/ffd6624af98db361025b to your computer and use it in GitHub Desktop.
Save hapticdata/ffd6624af98db361025b to your computer and use it in GitHub Desktop.
extract the unique colors out of an image
module.exports = uniqueColors;
var _canvas;
/**
* Collect all of the unique colors within an image,
* all pixel values are returned as [ red, green, blue, alpha ] between 0 - 255
* @param {Image|HTMLCanvasElement} image
* @param {Number} [x] to start sampling
* @param {Number} [y] to start sampling
* @param {Number} [width] to crop sampling
* @param {Number} [height] to crop sampling
* @param {Boolean} [ignoreAlphaZero] dismiss color values that are completely transparent
* @param {Number} [tolerance] dismiss a color if its difference to an existing color is under this tolerance
* @param {Array} [arr] provide an array to continue filling
* @return {Array<Array[4]>}
*/
function uniqueColors(image, x, y, width, height, ignoreAlphaZero, tolerance, arr){
x = x || 0;
y = y || 0;
width = width || image.naturalWidth;
height = height || image.naturalHeight;
ignoreAlphaZero = !!ignoreAlphaZero;
var checkTolerance = typeof tolerance === 'number';
arr = arr || [];
var canvas,
ctx,
colorKey,
colorMap = {};
if(image.getContext){
canvas = image;
ctx = canvas.getContext('2d');
} else {
//we can reuse the same canvas always
canvas = _canvas || (_canvas = document.createElement('canvas'));
canvas.width = image.width;
canvas.height = image.height;
ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight);
}
//now we have a canvas with the image painted on it
var imgData,
data,
i = 0,
r,
g,
b,
a;
try {
imgData = ctx.getImageData(x, y, width, height);
data = imgData.data;
} catch(e){
//if an error occurs, such as from trying to illegally use a
//cross-domain resource, dispose of the canvas to avoid future issues
_canvas = null;
throw e;
}
for(i=0; i<data.length; i+=4){
a = data[i+3];
if(a === 0 && ignoreAlphaZero){
continue;
}
r = data[i];
g = data[i+1];
b = data[i+2];
colorKey = r+'|'+g+'|'+b+'|'+a;
var px = [ r, g, b, a ];
if(!colorMap[colorKey]){
colorMap[colorKey] = px;
if(!checkTolerance || diffAll(arr, px, tolerance)){
arr.push(px);
}
}
}
return arr;
}
function difference(a, b) {
var diff = 0;
for(var i=0; i<a.length; i++){
diff += Math.abs(a[i] - b[i]);
}
return diff;
}
function diffAll(arr, a, tolerance){
for(var i=0; i<arr.length; i++){
if(difference(a, arr[i]) < tolerance){
return false;
}
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment