toxi.in.process

Tuesday, April 25, 2006

Colour code snippets

I needed to sort a given colour palette by certain criterias, for example by luminance, saturation or by proximity to another colour. This, for instance, comes quite handy when trying to bias a random colour choice using a fixed palette (e.g. favour darker over brighter colours in the palette or pick more yellow shades than blue). Am sure such a readymade util exists in some form, but sometimes writing stuff yourself is quicker and more worthwhile than googling for it. So DIY won yet again with the 3 results below:

/**
* sorts a given colour palette by saturation
* @param cols array of integers in standard packed (A)RGB format
* @return sorted version of array with element at last index
* containing the most saturated item of the palette
*/
int[] sortBySaturation(int[] cols) {
int[] sorted=new int[cols.length];
Hashtable ht=new Hashtable();
for(int i=0; i<cols.length; i++) {
int r=(cols[i]>>16) & 0xff;
int g=(cols[i]>>8) & 0xff;
int b=cols[i] & 0xff;
int maxComp = max(r,g,b);
if (maxComp > 0) {
sorted[i]=(int)((maxComp - min(r,g,b)) / (float)maxComp * 0x7fffffff);
}
else
sorted[i]=0;
ht.put(new Integer(sorted[i]),new Integer(cols[i]));
}
sorted=sort(sorted);
for(int i=0; i<sorted.length; i++) {
sorted[i]=((Integer)ht.get(new Integer(sorted[i]))).intValue();
}
return sorted;
}

/**
* sorts a given colour palette by luminance
* @param cols array of integers in standard packed (A)RGB format
* @return sorted version of array with element at last index
* containing the "brightest" item of the palette
*/

int[] sortByLuminance(int[] cols) {
int[] sorted=new int[cols.length];
Hashtable ht=new Hashtable();
for(int i=0; i<cols.length; i++) {
// luminance = 0.3*red + 0.59*green + 0.11*blue
// same equation in fixed point math...
sorted[i]=(77*(cols[i]>>16&0xff) + 151*(cols[i]>>8&0xff) + 28*(cols[i]&0xff));
ht.put(new Integer(sorted[i]),new Integer(cols[i]));
}
sorted=sort(sorted);
for(int i=0; i<sorted.length; i++) {
sorted[i]=((Integer)ht.get(new Integer(sorted[i]))).intValue();
}
return sorted;
}

/**
* sorts a given colour palette by proximity to a colour
* @param cols array of integers in standard packed (A)RGB format
* @param basecol colour to which proximity of all palette items is calculated
* @return sorted version of array with element at first index
* containing the "closest" item of the palette
*/

int[] sortByProximity(int[] cols,int basecol) {
int[] sorted=new int[cols.length];
Hashtable ht=new Hashtable();
int br=(basecol>>16) & 0xff;
int bg=(basecol>>8) & 0xff;
int bb=basecol & 0xff;
for(int i=0; i<cols.length; i++) {
int r=(cols[i]>>16) & 0xff;
int g=(cols[i]>>8) & 0xff;
int b=cols[i] & 0xff;
sorted[i]=(br-r)*(br-r)+(bg-g)*(bg-g)+(bb-b)*(bb-b);
ht.put(new Integer(sorted[i]),new Integer(cols[i]));
}
sorted=sort(sorted);
for(int i=0; i<sorted.length; i++) {
sorted[i]=((Integer)ht.get(new Integer(sorted[i]))).intValue();
}
return sorted;
}

Added bonus: Using a webcam and applying the 2nd function (sortByLuminance) to the contents of the current pixel buffer, you can instantly and possibly unintentionally create a close copy of this "amazing" piece of "infoviz" concept art... Sorted! :)

Also, I wasn't sure whether I should continue posting code snippets like this to this blog. A year ago I set up an account with Code Snippets which used to be more Ruby, JS and generally webdev oriented, but meanwhile has quite a big range of languages and subjects covered. Then of course there's also Processinghacks, but it didn't seem fitting for this either...