private int median_cut(box[] boxlist, int numboxes, int desired_colors)
{
while (numboxes < desired_colors)
{
/* Select box to split.
* Current algorithm: by population for first half, then by volume.
*/
int foundIndex;
if (numboxes * 2 <= desired_colors)
foundIndex = find_biggest_color_pop(boxlist, numboxes);
else
foundIndex = find_biggest_volume(boxlist, numboxes);
if (foundIndex == -1) /* no splittable boxes left! */
break;
/* Copy the color bounds to the new box. */
boxlist[numboxes].c0max = boxlist[foundIndex].c0max;
boxlist[numboxes].c1max = boxlist[foundIndex].c1max;
boxlist[numboxes].c2max = boxlist[foundIndex].c2max;
boxlist[numboxes].c0min = boxlist[foundIndex].c0min;
boxlist[numboxes].c1min = boxlist[foundIndex].c1min;
boxlist[numboxes].c2min = boxlist[foundIndex].c2min;
/* Choose which axis to split the box on.
* Current algorithm: longest scaled axis.
* See notes in update_box about scaling distances.
*/
int c0 = ((boxlist[foundIndex].c0max - boxlist[foundIndex].c0min) << C0_SHIFT) * R_SCALE;
int c1 = ((boxlist[foundIndex].c1max - boxlist[foundIndex].c1min) << C1_SHIFT) * G_SCALE;
int c2 = ((boxlist[foundIndex].c2max - boxlist[foundIndex].c2min) << C2_SHIFT) * B_SCALE;
/* We want to break any ties in favor of green, then red, blue last.
* This code does the right thing for R,G,B or B,G,R color orders only.
*/
int cmax = c1;
int n = 1;
if (c0 > cmax)
{
cmax = c0;
n = 0;
}
if (c2 > cmax)
{
n = 2;
}
/* Choose split point along selected axis, and update box bounds.
* Current algorithm: split at halfway point.
* (Since the box has been shrunk to minimum volume,
* any split will produce two nonempty subboxes.)
* Note that lb value is max for lower box, so must be < old max.
*/
int lb;
switch (n)
{
case 0:
lb = (boxlist[foundIndex].c0max + boxlist[foundIndex].c0min) / 2;
boxlist[foundIndex].c0max = lb;
boxlist[numboxes].c0min = lb + 1;
break;
case 1:
lb = (boxlist[foundIndex].c1max + boxlist[foundIndex].c1min) / 2;
boxlist[foundIndex].c1max = lb;
boxlist[numboxes].c1min = lb + 1;
break;
case 2:
lb = (boxlist[foundIndex].c2max + boxlist[foundIndex].c2min) / 2;
boxlist[foundIndex].c2max = lb;
boxlist[numboxes].c2min = lb + 1;
break;
}
/* Update stats for boxes */
update_box(boxlist, foundIndex);
update_box(boxlist, numboxes);
numboxes++;
}
return numboxes;
}