home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1990-1992 Michael Davidson.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation.
- *
- * This software is provided "as is" without express or implied warranty.
- */
-
- #include <stdio.h>
-
- #ifndef STATIC
- #define STATIC static
- #endif
-
- /*
- * median cut color quantization
- */
-
- #define BITS_PER_RGB 5
- #define MAX_PIXVAL ((1 << BITS_PER_RGB) - 1)
- #define MAX_COLORS (1 << 15)
-
- #define RED_SHIFT 10
- #define GREEN_SHIFT 5
- #define BLUE_SHIFT 0
- #define COLOR_MASK 0x1f
-
- #define RED(p) ( ((p) >> RED_SHIFT) & COLOR_MASK )
- #define GREEN(p) ( ((p) >> GREEN_SHIFT) & COLOR_MASK )
- #define BLUE(p) ( ((p) >> BLUE_SHIFT) & COLOR_MASK )
-
- #define RED_SORT(p, n) color_sort(p, n, RED_SHIFT)
- #define GREEN_SORT(p, n) color_sort(p, n, GREEN_SHIFT)
- #define BLUE_SORT(p, n) color_sort(p, n, BLUE_SHIFT)
-
- extern void *alloca(int);
-
- typedef struct color
- {
- unsigned char red;
- unsigned char green;
- unsigned char blue;
- } color_t;
-
- struct box
- {
- int index;
- int colors;
- int sum;
- };
-
- STATIC void sort_box();
- STATIC void split_box();
- STATIC void average_box();
- STATIC void color_sort();
-
- void
- quantize(
- unsigned long *histogram,
- color_t *colormap,
- unsigned char *lookup,
- int newcolors
- )
- {
- unsigned colors;
- unsigned sum;
- unsigned short *color_vec;
- unsigned short *cp;
- struct box box[256];
- int boxes;
- int i, j;
-
- /*
- * count the total number of colors
- */
- colors = 0;
- sum = 0;
-
- for (i = 0; i < MAX_COLORS; i++)
- {
- if (histogram[i] != 0)
- {
- sum += histogram[i];
- colors++;
- }
- }
-
- /*
- * build a table of all the colors that were found
- */
- color_vec = alloca(colors * sizeof(color_vec[0]));
- cp = color_vec;
-
- for (i = 0; i < MAX_COLORS; i++)
- {
- if (histogram[i] != 0)
- *cp++ = i;
- }
-
- /*
- * put all of the colors in the first box
- */
- box[0].index = 0;
- box[0].colors = colors;
- box[0].sum = sum;
- boxes = 1;
-
- /*
- * split the boxes until we have the desired number of colors
- */
-
- while (boxes < newcolors)
- {
- /*
- * Find the first splittable box.
- */
- for (i = 0, j = 0; i < boxes; i++ )
- if (box[i].colors > box[j].colors)
- j = i;
-
- if (box[j].colors <= 1)
- break;
- /*
- * sort the box
- */
- sort_box(&box[j], color_vec);
-
- split_box(&box[j], &box[boxes++], color_vec, histogram);
- }
-
- for (i = 0; i < boxes; i++)
- {
- int j;
- int index = box[i].index;
- int colors = box[i].colors;
-
- average_box(&box[i], color_vec, histogram, &colormap[i]);
-
- for (j = 0; j < colors; j++)
- lookup[color_vec[index + j]] = (unsigned char) i;
- }
-
- }
-
- STATIC void
- sort_box(
- struct box *bp,
- unsigned short *cv
- )
- {
- unsigned maxr, minr;
- unsigned maxg, ming;
- unsigned maxb, minb;
- int i;
- int n;
-
- /*
- * find the range of rgb components in this box
- */
- minr =
- ming =
- minb = MAX_PIXVAL;
-
- maxr =
- maxg =
- maxb = 0;
-
- for (i = bp->index, n = bp->colors; --n >= 0; i++)
- {
- register unsigned color;
- register unsigned v;
-
- color = cv[i];
-
- v = RED(color);
- if ( v < minr ) minr = v;
- if ( v > maxr ) maxr = v;
- v = GREEN(color);
- if ( v < ming ) ming = v;
- if ( v > maxg ) maxg = v;
- v = BLUE(color);
- if ( v < minb ) minb = v;
- if ( v > maxb ) maxb = v;
- }
-
- /*
- * now choose which color to sort by
- */
-
- maxr = (maxr - minr) * 77;
- maxg = (maxg - ming) * 150;
- maxb = (maxb - minb) * 29;
-
- if (maxr >= maxg && maxr >= maxb)
- RED_SORT(&cv[bp->index], bp->colors);
- else if (maxg >= maxb)
- GREEN_SORT(&cv[bp->index], bp->colors);
- else
- BLUE_SORT(&cv[bp->index], bp->colors);
- }
-
- STATIC void
- split_box(
- struct box *bp,
- struct box *np,
- unsigned short *cv,
- unsigned long *hist
- )
- {
- int i;
- int idx;
- int median;
- int sum;
-
- median = bp->sum / 2;
-
- idx = bp->index;
- sum = hist[cv[idx++]];
-
- for (i = 1; i < bp->colors - 1; i++)
- {
- if (sum >= median)
- break;
-
- sum += hist[cv[idx++]];
- }
-
-
-
- *np = *bp;
-
- np->index += i;
- np->colors -= i;
- np->sum -= sum;
-
- bp->colors = i;
- bp->sum = sum;
- }
-
- STATIC void
- average_box(
- struct box *bp,
- unsigned short *cv,
- unsigned long *hist,
- color_t *cmap
- )
- {
-
- int index = bp->index;
- int colors= bp->colors;
-
- long r = 0, g = 0, b = 0, sum = 0;
- register int i;
-
- if (colors == 0)
- return;
-
- for (i = 0; i < colors; i++)
- {
- unsigned long value;
- register unsigned color;
-
- color = cv[index + i];
- value = hist[color];
- r += RED(color) * value;
- g += GREEN(color) * value;
- b += BLUE(color) * value;
- sum += value;
- }
-
- r *= 8;
- r = r / sum;
- if ( r > 255 ) r = 255;
- g *= 8;
- g = g / sum;
- if ( g > 255 ) g = 255;
- b *= 8;
- b = b / sum;
- if ( b > 255 ) b = 255;
-
- cmap->red = (unsigned char) r;
- cmap->green = (unsigned char) g;
- cmap->blue = (unsigned char) b;
- }
-
-
- STATIC void
- color_sort(
- register unsigned short *p,
- int n,
- register int shift
- )
- {
- unsigned long count[MAX_PIXVAL+1];
- unsigned short *temp_vec;
- register int i;
-
- #define COLOR(p) (((p) >> shift) & COLOR_MASK)
-
- temp_vec = alloca(n * sizeof(temp_vec[0]));
-
- for (i = 0; i <= MAX_PIXVAL; i++)
- count[i] = 0;
-
- for (i = 0; i < n; i++)
- count[COLOR(p[i])] ++;
-
- for (i = 1; i <= MAX_PIXVAL; i++)
- count[i] += count[i-1];
-
- for (i = n; --i >= 0; )
- temp_vec[--count[COLOR(p[i])]] = p[i];
-
- for (i = 0; i < n; i++)
- p[i] = temp_vec[i];
- }
-
-