home *** CD-ROM | disk | FTP | other *** search
- /*
- getmap.c
- 1995-07-02
- by T.Ogihara (ogihara@seg.kobe-u.ac.jp)
-
- Checks number of color used in the image.
- Reduces color by median cut algorithm (MCA) of Paul Heckbert.
- This code refers to "ppmquant" of Jef Poskanzer, but, in
- many cases, this program could generate more beautiful image.
- */
-
-
- #include <stdlib.h>
- #include <string.h>
- #include <appkit/color.h>
- #include "common.h"
- #include "save.h"
-
- #define EnoughMemory 1
-
- #if EnoughMemory
- # define COLORSTEPS 65536 /* = 0x10000 */
- # define MAXColors 62000 /* < COLORSTEPS */
- # define ColorHash(r,g,b) ( ((r)<<8) | (g) ) /* Hash KEY */
- # define ColorHnew(x) (((x) + 5987) & 0xffff)
- typedef int indexint;
- #else
- # define COLORSTEPS 32768 /* = 32 ^ 3 = 0x8000 */
- # define MAXColors 30000 /* < COLORSTEPS */
- # define ColorHash(r,g,b) ( ((r)<<7) | ((g) & 0x7f) ) /* Hash KEY */
- # define ColorHnew(x) (((x) + 5987) & 0x7fff)
- typedef short indexint;
- #endif
-
- typedef struct {
- int count;
- unsigned char red, green, blue;
- unsigned char palidx; /* index for palette */
- } tabcell;
-
- typedef struct {
- int index, colors;
- int sum;
- } element;
-
- /* quick sort */
- static int q_red(int);
- static int q_green(int);
- static int q_blue(int);
- static int q_colors(int);
- static int q_count(int);
- static int q_palette(int);
- static void inssort(int, indexint *, int (*)(int));
- static void quicksort(int, indexint *, int (*)(int));
-
- static tabcell *hashtab = NULL;
- static indexint *pindex = NULL;
- static paltype *pal = NULL;
- static int colornum, totalnum;
- static float darkfactor = 0.0;
- static int darken = 0;
-
-
- static int hashIndex(int r, int g, int b)
- {
- tabcell *tp;
- int x = ColorHash(r,g,b);
-
- tp = &hashtab[x];
- while (tp->count > 0
- && (tp->red != r || tp->green != g || tp->blue != b))
- tp = &hashtab[x = ColorHnew(x)];
- if (tp->count == 0) {
- tp->red = r;
- tp->green = g;
- tp->blue = b;
- colornum++;
- }
- tp->count++;
- return x;
- }
-
- void free256map(void)
- {
- if (hashtab) free((void *)hashtab);
- hashtab = NULL;
- if (pindex) free((void *)pindex);
- pindex = NULL;
- if (pal) free((void *)pal);
- pal = NULL;
- }
-
- int getAllColor(int *cnum, unsigned char **map)
- /* »¨⁄õ⁄ò⁄˘⁄⁄⁄º¿§¿û⁄ù cnum⁄¸˘⁄ò⁄º¡£
- ¿§¿û⁄‹´¿⁄„⁄fi⁄˘¿û⁄¤⁄Ø⁄ò⁄˚⁄⁄»⁄ˇ COLORSTEPS ⁄‹ cnum ⁄¸˘⁄Œ¡¢
- ˚±¿û colornum ⁄ˇ£®⁄¸¥»¥ˆ¥¨⁄¦⁄ò⁄º¡£
- ˚á⁄Œˆ˝⁄ˇ¥¤¥Ø¡…⁄ù²‰⁄„¡£ */
- {
- int r, g, b, i;
-
- if (hashtab == NULL) {
- if ((hashtab = (tabcell *)calloc(COLORSTEPS, sizeof(tabcell))) == NULL
- || (pindex = (indexint *)calloc(COLORSTEPS, sizeof(indexint))) == NULL
- || (pal = (paltype *)calloc(FIXcount, sizeof(paltype))) == NULL) {
- free256map();
- *cnum = 0;
- return Err_MEMORY;
- }
- }
- for (i = 0; i < COLORSTEPS; i++)
- pindex[i] = i;
-
- resetPixel(map, 0);
- colornum = 0;
- while (getPixel(&r, &g, &b) >= 0) {
- (void) hashIndex(r,g,b);
- if (colornum >= MAXColors) { /* Too many color */
- *cnum = COLORSTEPS;
- colornum = 0;
- return 0;
- }
- }
- *cnum = colornum;
- return 0;
- }
-
- int getAllPalColor(void)
- /* ¥±¥ò¥ˆ¥¨⁄˛ˆð⁄˛¿§⁄ù˜·⁄ä¡¢¥ˇ¥ˆ¥•¥ï²‰⁄¸¯—ˇ¿⁄•⁄˘⁄“⁄fl¡£ */
- {
- int r, g, b, i;
-
- pal = NULL;
- pindex = NULL;
- if (hashtab == NULL) {
- hashtab = (tabcell *)calloc(COLORSTEPS, sizeof(tabcell));
- if (hashtab == NULL) {
- free256map();
- return Err_MEMORY;
- }
- }
- colornum = 0;
- darken = 0;
- for (i = 0; getPalPixel(&r, &g, &b) >= 0; i++)
- hashtab[hashIndex(r,g,b)].palidx = i;
- return 0;
- }
-
-
- paltype *getNormalmap(int *cnum)
- /* getAllColor() ⁄˛‚ï⁄˙»¨⁄⁄¡¢¥±¥ò¥ˆ¥¨⁄ù˚á⁄„¡£
- »¨⁄õ⁄ò⁄˘⁄⁄⁄º¿§⁄‹ 256¿§®˚˘í⁄˙⁄¢⁄º⁄‡⁄¨¡£ */
- {
- unsigned char *p;
- tabcell *t;
- int i, x, num;
-
- quicksort(COLORSTEPS, pindex, q_colors);
- for (i = 0, num = 0; i < COLORSTEPS && num < FIXcount; i++) {
- if (hashtab[x = pindex[i]].count == 0) continue;
- t = &hashtab[x];
- p = pal[num];
- p[RED] = t->red;
- p[GREEN] = t->green;
- p[BLUE] = t->blue;
- t->palidx = num++;
- }
- darken = 0;
- *cnum = num;
- return pal;
- }
-
- int reduce_bright(int *cnum, float *bright, unsigned char **map)
- /* getAllColor() ⁄˛‚ï⁄˙»¨⁄ƒ¡£³¹⁄º⁄¦⁄ù‚”⁄Ø⁄•⁄˘¿§⁄ù˘²⁄ë„⁄똬⁄„¡£
- *bright ⁄‹ 0.0 ⁄˚⁄Ø”˙‰Ø⁄˛»ô„¾⁄¹⁄‹¡¢⁄‰⁄ò®˚‡®⁄˚⁄Ø⁄—‚”¿§⁄˛•«⁄Œ˚á⁄•
- ⁄˛¯½ˆð⁄˙⁄¢⁄º¡£⁄‡⁄ò⁄ˇ¡¢¯½ˆð⁄˙•—†Æ˚ú„ö⁄ù„¾⁄ƒ⁄¿⁄Æ⁄˙⁄¢⁄º¡£
- …”˙¾⁄•⁄¿⁄Ø¡¢*bright⁄¸…¡†ú⁄˛¥±¥Ø¥Æ¡…¥¿⁄ù˘⁄ò¡¢£®⁄ù˚á⁄„¡£*/
- {
- int r, g, b;
- static float fact[] = {
- 0.0, 1.0, 0.96, 0.875, 0.75, 0.625, 0.5,
- 0.4, 0.3, 0.25, 0.2, 0.16667, 0.13333, 0.1, 0.0 };
-
- if (*bright < 0.01) { /* == 0.0 */
- *bright = fact[darken = 1];
- return 0;
- }
- darkfactor = fact[darken];
- bzero((void *)hashtab, sizeof(tabcell)*COLORSTEPS);
- resetPixel(map, 0);
- colornum = 0;
- totalnum = 0;
- while (getPixel(&r, &g, &b) >= 0) {
- r = (int)(r * darkfactor + 0.9) & 0xfe;
- g = (int)(g * darkfactor + 0.9) & 0xfe;
- b = (int)(b * darkfactor + 0.9) & 0xfe;
- (void) hashIndex(r,g,b);
- totalnum++;
- if (colornum >= MAXColors) { /* Too many color */
- colornum = 0;
- *bright = fact[++darken];
- return 0;
- }
- }
- *bright = 0.0;
- return 1;
- }
-
- int mapping(int r, int g, int b)
- {
- if (darken) {
- r = (int)(r * darkfactor + 0.9) & 0xfe;
- g = (int)(g * darkfactor + 0.9) & 0xfe;
- b = (int)(b * darkfactor + 0.9) & 0xfe;
- }
- return hashtab[hashIndex(r,g,b)].palidx;
- }
-
-
- static void SortMaxElement(int indx, int clrs)
- {
- int i, j, end;
- unsigned short min[3], max[3], val[3];
- float bright[3];
- tabcell *t;
-
- /* Find the minimum and maximum of each component */
- for (i = 0; i < 3; i++)
- min[i] = 255, max[i] = 0;
- end = indx + clrs;
- for (i = indx; i < end; i++) {
- t = &hashtab[pindex[i]];
- if (t->count == 0)
- continue;
- val[RED] = t->red;
- val[GREEN] = t->green;
- val[BLUE] = t->blue;
- for (j = 0; j < 3; j++) {
- if (min[j] > val[j]) min[j] = val[j];
- if (max[j] < val[j]) max[j] = val[j];
- }
- }
- /* calculate brightness */
- bright[RED] = (max[RED] - min[RED]) * 0.299;
- bright[GREEN] = (max[GREEN] - min[GREEN]) * 0.587;
- bright[BLUE] = (max[BLUE] - min[BLUE]) * 0.114;
- if ( bright[RED] >= bright[GREEN] && bright[RED] >= bright[BLUE] )
- quicksort(clrs, &pindex[indx], q_red);
- else if ( bright[GREEN] >= bright[BLUE] )
- quicksort(clrs, &pindex[indx], q_green);
- else
- quicksort(clrs, &pindex[indx], q_blue);
- }
-
- static void makepalette(element *elm, int cellnum)
- {
- int indx, clrs, i, ex, best;
- long r, g, b, w, sum;
- unsigned char *p;
- tabcell *t;
-
- for (ex = 0; ex < cellnum; ex++) {
- indx = elm[ex].index;
- clrs = elm[ex].colors;
- r = g = b = 0, sum = 0;
- p = pal[ex];
-
- w = indx + clrs;
- for (i = indx; i < w; i++) {
- int c = (t = &hashtab[pindex[i]])->count;
- r += t->red * c;
- g += t->green * c;
- b += t->blue * c;
- sum += c;
- }
- p[RED] = ((r /= sum) < 256) ? r : 255;
- p[GREEN] = ((g /= sum) < 256) ? g : 255;
- p[BLUE] = ((b /= sum) < 256) ? b : 255;
- }
- /* Values of pindex[] are not used any more.
- Sort the palette. */
- for (i = 0; i < cellnum; i++)
- pindex[i] = i;
- quicksort(cellnum, pindex, q_palette);
- for (ex = 0; ex < cellnum; ex++) {
- unsigned char *q;
- int x, y;
- x = pindex[ex];
- if (ex == x) continue;
- for (y = ex+1; y < cellnum; y++)
- if (pindex[y] == ex) break;
- p = pal[x];
- q = pal[ex];
- for (i = 0; i < 3; i++)
- r = p[i], p[i] = q[i], q[i] = r;
- pindex[ex] = ex;
- pindex[y] = x;
- }
-
- for (i = 0; i < COLORSTEPS; i++) {
- if (hashtab[i].count == 0) continue;
- t = &hashtab[i];
- r = t->red;
- g = t->green;
- b = t->blue;
- w = 4 * 256 * 256;
- best = 0;
- for (ex = 0; ex < cellnum; ex++) {
- long rr, gg, bb;
- p = pal[ex];
- rr = r - p[RED];
- gg = g - p[GREEN];
- bb = b - p[BLUE];
- if ((sum = rr*rr + gg*gg + bb*bb) < w)
- w = sum, best = ex;
- }
- t->palidx = best;
- }
- }
-
- paltype *get256map(int *cnum)
- {
- int i, w;
- element elm[FIXcount];
- int elmptr, curelm;
- int indx, clrs, sm;
- int halfsum, lowersum;
-
- quicksort(COLORSTEPS, pindex, q_count);
- for (i = 0; i < COLORSTEPS; i++)
- if (hashtab[pindex[i]].count) break;
- elm[0].index = i;
- elm[0].colors = COLORSTEPS - i;
- elm[0].sum = totalnum;
- elmptr = 1;
-
- while (elmptr < FIXcount) {
- /* Find largest element */
- curelm = -1;
- w = 2; /* should be divided */
- for (i = 0; i < elmptr; i++) {
- if (elm[i].colors >= w)
- w = elm[curelm = i].colors;
- }
- if (curelm < 0)
- break; /* all color was found */
- indx = elm[curelm].index;
- clrs = elm[curelm].colors;
- sm = elm[curelm].sum;
- SortMaxElement(indx, clrs);
-
- /* Find the median */
- w = clrs - 1;
- lowersum = 0;
- halfsum = sm / 2;
- for (i = 0; i < w && lowersum < halfsum; i++)
- lowersum += hashtab[pindex[indx + i]].count;
-
- /* Divide the box */
- elm[curelm].colors = i;
- elm[curelm].sum = lowersum;
- elm[elmptr].index = indx + i;
- elm[elmptr].colors = clrs - i;
- elm[elmptr].sum = sm - lowersum;
- ++elmptr;
- }
-
- makepalette(elm, elmptr);
- *cnum = elmptr;
- return pal;
- }
-
- /* ----------------------------------------------------------------
- QUICK SORT by Haruhiko Okumura
- –þ´…¹†²§¡á£ˆ‚¹‚ò⁄¸⁄Ł⁄º”˙¿•¥¢¥º¥·¥Œ¥”¥ì»ü¯¦¡â¡˚¦»‰±²¬ˇ¹…¼¡¸
- modified by T. Ogihara
- ----------------------------------------------------------------- */
-
- static int q_red(int x) { return hashtab[x].red; }
- static int q_green(int x) { return hashtab[x].green; }
- static int q_blue(int x) { return hashtab[x].blue; }
- static int q_count(int x) { return hashtab[x].count; }
- static int q_colors(int x) {
- tabcell *t = &hashtab[x];
- return (t->count)
- ? ((t->red << 16) | (t->green << 8) | t->blue) : 0;
- }
- static int q_palette(int x) {
- unsigned char *p = pal[x];
- return ((p[RED] << 16) | (p[GREEN] << 8) | p[BLUE]);
- }
-
- static void inssort(int n, indexint *a, int (*qval)(int))
- {
- int i, j, val;
- indexint x;
-
- for (i = 1; i < n; i++) {
- val = qval(x = a[i]);
- for (j = i - 1; j >= 0 && qval(a[j]) > val; j--)
- a[j + 1] = a[j];
- a[j + 1] = x;
- }
- }
-
- #define THRESHOLD 10
- #define STACKSIZE 32 /* ⁄¿⁄«⁄¹⁄« int ⁄˛¥½¥ˆ¥¨¿û˜ł¯ä */
-
- static void quicksort(int n, indexint *ar, int (*qval)(int))
- {
- int i, j, left, right, p;
- int leftstack[STACKSIZE], rightstack[STACKSIZE];
- indexint t;
- int x;
-
- left = 0; right = n - 1; p = 0;
- for ( ; ; ) {
- if (right - left <= THRESHOLD) {
- if (p == 0) break;
- p--;
- left = leftstack[p];
- right = rightstack[p];
- }
- x = qval(ar[(left + right) / 2]);
- i = left; j = right;
- for ( ; ; ) {
- while (qval(ar[i]) < x) i++;
- while (x < qval(ar[j])) j--;
- if (i >= j) break;
- t = ar[i]; ar[i] = ar[j]; ar[j] = t;
- i++; j--;
- }
- if (i - left > right - j) {
- if (i - left > THRESHOLD) {
- leftstack[p] = left;
- rightstack[p] = i - 1;
- p++;
- }
- left = j + 1;
- } else {
- if (right - j > THRESHOLD) {
- leftstack[p] = j + 1;
- rightstack[p] = right;
- p++;
- }
- right = i - 1;
- }
- }
- inssort(n, ar, qval);
- }
-