diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/x11iraf/ximtool/quant.c | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'vendor/x11iraf/ximtool/quant.c')
-rw-r--r-- | vendor/x11iraf/ximtool/quant.c | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/vendor/x11iraf/ximtool/quant.c b/vendor/x11iraf/ximtool/quant.c new file mode 100644 index 00000000..34514a50 --- /dev/null +++ b/vendor/x11iraf/ximtool/quant.c @@ -0,0 +1,797 @@ +#include <stdio.h> + +/* QUANT.C -- Quantize the colors in a pixmap down to a specified number. +** This code is largely stolen from PBMPlus by Jef Poskanzer. +** +** ORIGINAL COPYRIGHT NOTICE: +** +** Copyright (C) 1989, 1991 by Jef Poskanzer. +** +** 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. +*/ + +#undef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#undef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#undef abs +#define abs(a) ((a) >= 0 ? (a) : -(a)) +#undef odd +#define odd(n) ((n) & 1) + +#ifdef HPUX +#define random() rand() +#define srandom(x) srand(x) +#endif + +typedef unsigned char byte; +typedef unsigned char pixval; + +#define PPM_MAXMAXVAL 255 +typedef struct { pixval r, g, b; } pixel; + +#define PPM_GETR(p) ((p).r) +#define PPM_GETG(p) ((p).g) +#define PPM_GETB(p) ((p).b) + +#define PPM_ASSIGN(p,red,grn,blu) \ + { (p).r = (red); (p).g = (grn); (p).b = (blu); } + +#define PPM_EQUAL(p,q) ( (p).r == (q).r && (p).g == (q).g && (p).b == (q).b ) + +/* Color scaling macro -- to make writing ppmtowhatever easier. */ +#define PPM_DEPTH(newp,p,oldmaxval,newmaxval) \ + PPM_ASSIGN( (newp), \ + (int) PPM_GETR(p) * (newmaxval) / (oldmaxval), \ + (int) PPM_GETG(p) * (newmaxval) / (oldmaxval), \ + (int) PPM_GETB(p) * (newmaxval) / (oldmaxval) ) + +/* Luminance macro, using only integer ops. Returns an int (*256) JHB */ +#define PPM_LUMIN(p) \ + ( 77 * PPM_GETR(p) + 150 * PPM_GETG(p) + 29 * PPM_GETB(p) ) + + +/* Color histogram stuff. */ +typedef struct colorhist_item *colorhist_vector; +struct colorhist_item { + pixel color; + int value; +}; + +typedef struct colorhist_list_item *colorhist_list; +struct colorhist_list_item { + struct colorhist_item ch; + colorhist_list next; +}; + + +/* Color hash table stuff. */ + +typedef colorhist_list *colorhash_table; + +#define MAXCOLORS 32767 +#define FS_SCALE 1024 +#define HASH_SIZE 20023 + +#define LARGE_LUM +#define REP_AVERAGE_PIXELS + +#define hashPixel(p) ((((int) PPM_GETR(p) * 33023 + \ + (int) PPM_GETG(p) * 30013 + \ + (int) PPM_GETB(p) * 27011) & 0x7fffffff) \ + % HASH_SIZE) + + +typedef struct box *box_vector; +struct box { + int ind; + int colors; + int sum; +}; + +static colorhist_vector medianCut (), colorHashToColorHist (); +static colorhist_vector computeColorHist (); +static colorhash_table computeColorHash (), colorHistToColorHash (); +static colorhash_table allocColorHash (); +static int redCompare(), greenCompare(), blueCompare(); +static int lookupColor (), addToColorHash (), sumCompare(); +static void freeColorHash (), addToColorHist(),freeColorHist(); + + + +/* PPMQUANT -- Quantize an image with a given colormap to a new number of + * colors, modifies the image in place. Floyd-Steinberg dithering isn't + * current enabled because of speed but can be turned on later. Modified + * from the original code in the PBMplus package by Jef Poskanzer. + */ + +int +ppmquant (image, r, g, b, nx, ny, ncolors, newcolors) +byte *image; /* image pixels (i.e. cmap indices) */ +byte *r, *g, *b; /* colormap */ +int nx, ny; /* image dimensions */ +int ncolors; /* current number of colors */ +int newcolors; /* requested number of colors */ +{ + register pixel *pP; + register long sr, sg, sb, err; + register int i, col, limitcol, index = 0; + byte *pix = image; + pixel **pixels; + pixval maxval = 255, newmaxval; + int rows, cols, row; + int colors; + int floyd = 0, usehash; + colorhist_vector chv, colormap; + colorhash_table cht; + long *thisrerr, *thisgerr, *thisberr; + long *nextrerr, *nextgerr, *nextberr, *temperr; + int fs_direction; + + /* Reformat into 2-dimensional array of pixel structures */ + rows = ny; + cols = nx; + pixels = (pixel **) malloc (rows * sizeof(pixel *)); + if (!pixels) + return; + + for (row=0; row<rows; row++) { + pixels[row] = (pixel *) malloc(cols * sizeof(pixel)); + if (!pixels[row]) + return; + + for (col=0, pP=pixels[row]; col<cols; col++, pP++) { + pP->r = (pixval) r[*pix]; + pP->g = (pixval) g[*pix]; + pP->b = (pixval) b[*pix]; + pix++; + } + } + + + /* Step 2: attempt to make a histogram of the colors, unclustered. + ** If at first we don't succeed, lower maxval to increase color + ** coherence and try again. This will eventually terminate, with + ** maxval at worst 15, since 32^3 is approximately MAXCOLORS. + */ + for (; ;) { + chv = computeColorHist(pixels, cols, rows, MAXCOLORS, &colors) ; + if (chv != (colorhist_vector) 0) + break; + newmaxval = maxval / 2; + for (row = 0; row < rows; ++row) + for (col = 0, pP = pixels[row]; col < cols; ++col, ++pP) + PPM_DEPTH (*pP, *pP, maxval, newmaxval) ; + maxval = newmaxval; + } + + /* Step 3: apply median-cut to histogram, making the new colormap. + */ + colormap = medianCut (chv, colors, rows * cols, maxval, newcolors) ; + freeColorHist (chv) ; + + /* Step 4: map the colors in the image to their closest match in the + ** new colormap, and write 'em out. + */ + cht = allocColorHash (); + usehash = 1; + pix = image; + if (floyd) { + /* Initialize Floyd-Steinberg error vectors. */ + thisrerr = (long *) calloc (cols + 2, sizeof(long) ); + nextrerr = (long *) calloc (cols + 2, sizeof(long) ); + thisgerr = (long *) calloc (cols + 2, sizeof(long) ); + nextgerr = (long *) calloc (cols + 2, sizeof(long) ); + thisberr = (long *) calloc (cols + 2, sizeof(long) ); + nextberr = (long *) calloc (cols + 2, sizeof(long) ); + srandom ((int) (time (0) ^ getpid ()) ) ; + for (col = 0; col < cols + 2; ++col) { + thisrerr[col] = random () % (FS_SCALE * 2) - FS_SCALE; + thisgerr[col] = random () % (FS_SCALE * 2) - FS_SCALE; + thisberr[col] = random () % (FS_SCALE * 2) - FS_SCALE; + /* (random errors in [-1 .. 1]) */ + } + fs_direction = 1; + } + for (row = 0; row < rows; ++row) { + if (floyd) + for (col = 0; col < cols + 2; ++col) + nextrerr[col] = nextgerr[col] = nextberr[col] = 0; + if ( (!floyd) || fs_direction) { + col = 0; + limitcol = cols; + pP = pixels[row]; + } else { + col = cols - 1; + limitcol = -1; + pP = &(pixels[row][col]); + } + do { + if (floyd) { + /* Use Floyd-Steinberg errors to adjust actual color. */ + sr = PPM_GETR(*pP) + thisrerr[col + 1] / FS_SCALE; + sg = PPM_GETG(*pP) + thisgerr[col + 1] / FS_SCALE; + sb = PPM_GETB(*pP) + thisberr[col + 1] / FS_SCALE; + if (sr < 0) + sr = 0; + else if (sr > maxval) + sr = maxval; + if (sg < 0) + sg = 0; + else if (sg > maxval) + sg = maxval; + if (sb < 0) + sb = 0; + else if (sb > maxval) + sb = maxval; + PPM_ASSIGN (*pP, sr, sg, sb) ; + } + + /* Check hash table to see if we have already matched this + * color. + */ + index = lookupColor (cht, pP) ; + if (index == -1) { /* No; search colormap for closest match. */ + register int i, r1, g1, b1, r2, g2, b2; + register long dist, newdist; + r1 = PPM_GETR (*pP) ; + g1 = PPM_GETG (*pP) ; + b1 = PPM_GETB (*pP) ; + dist = 2000000000; + for (i = 0; i < newcolors; ++i) { + r2 = PPM_GETR (colormap[i].color) ; + g2 = PPM_GETG (colormap[i].color) ; + b2 = PPM_GETB (colormap[i].color) ; + newdist = (r1 - r2) * (r1 - r2) + + (g1 - g2) * (g1 - g2) + + (b1 - b2) * (b1 - b2) ; + if (newdist < dist) { + index = i; + dist = newdist; + } + } + if (usehash) { + if (addToColorHash (cht, pP, index) < 0) { + usehash = 0; + } + } + } + + if (floyd) { + /* Propagate Floyd-Steinberg error terms. */ + if (fs_direction) { + err = (sr - (long) PPM_GETR (colormap[index].color)) * FS_SCALE; + thisrerr[col + 2] += (err * 7) / 16; + nextrerr[col ] += (err * 3) / 16; + nextrerr[col + 1] += (err * 5) / 16; + nextrerr[col + 2] += (err ) / 16; + err = (sg - (long) PPM_GETG (colormap[index].color)) * FS_SCALE; + thisgerr[col + 2] += (err * 7) / 16; + nextgerr[col ] += (err * 3) / 16; + nextgerr[col + 1] += (err * 5) / 16; + nextgerr[col + 2] += (err ) / 16; + err = (sb - (long) PPM_GETB (colormap[index].color)) * FS_SCALE; + thisberr[col + 2] += (err * 7) / 16; + nextberr[col ] += (err * 3) / 16; + nextberr[col + 1] += (err * 5) / 16; + nextberr[col + 2] += (err ) / 16; + } else { + + err = (sr - (long) PPM_GETR (colormap[index].color)) * FS_SCALE; + thisrerr[col ] += (err * 7) / 16; + nextrerr[col + 2] += (err * 3) / 16; + nextrerr[col + 1] += (err * 5) / 16; + nextrerr[col ] += (err ) / 16; + err = (sg - (long) PPM_GETG (colormap[index].color)) * FS_SCALE; + thisgerr[col ] += (err * 7) / 16; + nextgerr[col + 2] += (err * 3) / 16; + nextgerr[col + 1] += (err * 5) / 16; + nextgerr[col ] += (err ) / 16; + err = (sb - (long) PPM_GETB (colormap[index].color)) * FS_SCALE; + thisberr[col ] += (err * 7) / 16; + nextberr[col + 2] += (err * 3) / 16; + nextberr[col + 1] += (err * 5) / 16; + nextberr[col ] += (err ) / 16; + } + } + + *pP = colormap[index].color; + *pix++ = index; /* save the new image index */ + + if ( (!floyd) || fs_direction) { + ++col; + ++pP; + } else { + --col; + --pP; + } + } while (col != limitcol) ; + + if (floyd) { + temperr = thisrerr; + thisrerr = nextrerr; + nextrerr = temperr; + temperr = thisgerr; + thisgerr = nextgerr; + nextgerr = temperr; + temperr = thisberr; + thisberr = nextberr; + nextberr = temperr; + fs_direction = !fs_direction; + } + + } + + /* Rescale and load the new colormap. */ + for (i=0; i<newcolors; i++) { + PPM_DEPTH(colormap[i].color, colormap[i].color, maxval, 255); + r[i] = PPM_GETR (colormap[i].color); + g[i] = PPM_GETG (colormap[i].color); + b[i] = PPM_GETB (colormap[i].color); + } + + /* Free the pixels array. */ + for (i=0; i<rows; i++) free (pixels[i]); + free (pixels); + + /* Free cht and colormap. */ + freeColorHist (colormap); + freeColorHash (cht); + + return (0) ; +} + + +/* +** Here is the fun part, the median-cut colormap generator. This is based +** on Paul Heckbert's paper "Color Image Quantization for Frame Buffer +** Display", SIGGRAPH '82 Proceedings, page 297. +*/ + +static colorhist_vector +medianCut (chv, colors, sum, maxval, newcolors) +colorhist_vector chv; +int colors, sum, newcolors; +pixval maxval; +{ + colorhist_vector colormap; + box_vector bv; + register int bi, i; + int boxes; + + bv = (box_vector) malloc (sizeof(struct box) * newcolors) ; + colormap = + (colorhist_vector) malloc (sizeof(struct colorhist_item) * newcolors) ; + if (bv == (box_vector) 0 || colormap == (colorhist_vector) 0) + perror ("out of memory") ; + for (i = 0; i < newcolors; ++i) + PPM_ASSIGN (colormap[i].color, 0, 0, 0) ; + + /* + ** Set up the initial box. + */ + bv[0].ind = 0; + bv[0].colors = colors; + bv[0].sum = sum; + boxes = 1; + + /* + ** Main loop: split boxes until we have enough. + */ + while (boxes < newcolors) { + register int indx, clrs; + int sm; + register int minr, maxr, ming, maxg, minb, maxb, v; + int halfsum, lowersum; + + /* + ** Find the first splittable box. + */ + for (bi = 0; bi < boxes; ++bi) + if (bv[bi].colors >= 2) + break; + if (bi == boxes) + break; /* ran out of colors! */ + indx = bv[bi].ind; + clrs = bv[bi].colors; + sm = bv[bi].sum; + + /* + ** Go through the box finding the minimum and maximum of each + ** component - the boundaries of the box. + */ + minr = maxr = PPM_GETR (chv[indx].color) ; + ming = maxg = PPM_GETG (chv[indx].color) ; + minb = maxb = PPM_GETB (chv[indx].color) ; + for (i = 1; i < clrs; ++i) { + v = PPM_GETR (chv[indx + i].color) ; + if (v < minr) + minr = v; + if (v > maxr) + maxr = v; + v = PPM_GETG (chv[indx + i].color) ; + if (v < ming) + ming = v; + if (v > maxg) + maxg = v; + v = PPM_GETB (chv[indx + i].color) ; + if (v < minb) + minb = v; + if (v > maxb) + maxb = v; + } + + /* + ** Find the largest dimension, and sort by that component. I have + ** included two methods for determining the "largest" dimension; + ** first by simply comparing the range in RGB space, and second + ** by transforming into luminosities before the comparison. You + ** can switch which method is used by switching the commenting on + ** the LARGE_ defines at the beginning of this source file. + */ + { + /* LARGE_LUM version */ + + pixel p; + float rl, gl, bl; + + PPM_ASSIGN(p, maxr - minr, 0, 0); + rl = PPM_LUMIN(p); + PPM_ASSIGN(p, 0, maxg - ming, 0); + gl = PPM_LUMIN(p); + PPM_ASSIGN(p, 0, 0, maxb - minb); + bl = PPM_LUMIN(p); + + if (rl >= gl && rl >= bl) + qsort( + (char *)&(chv[indx]),clrs,sizeof(struct colorhist_item), + redCompare) ; + else if (gl >= bl) + qsort( + (char *)&(chv[indx]),clrs,sizeof(struct colorhist_item), + greenCompare) ; + else + qsort( + (char *)&(chv[indx]),clrs,sizeof(struct colorhist_item), + blueCompare) ; + } + + /* + ** Now find the median based on the counts, so that about half the + ** pixels (not colors, pixels) are in each subdivision. + */ + lowersum = chv[indx].value; + halfsum = sm / 2; + for (i = 1; i < clrs - 1; ++i) { + if (lowersum >= halfsum) + break; + lowersum += chv[indx + i].value; + } + + /* + ** Split the box, and sort to bring the biggest boxes to the top. + */ + bv[bi].colors = i; + bv[bi].sum = lowersum; + bv[boxes].ind = indx + i; + bv[boxes].colors = clrs - i; + bv[boxes].sum = sm - lowersum; + ++boxes; + qsort ((char *) bv, boxes, sizeof(struct box) , sumCompare) ; + } + + /* + ** Ok, we've got enough boxes. Now choose a representative color for + ** each box. There are a number of possible ways to make this choice. + ** One would be to choose the center of the box; this ignores any + ** structure within the boxes. Another method would be to average all + ** the colors in the box - this is the method specified in Heckbert's + ** paper. A third method is to average all the pixels in the box. You + ** can switch which method is used by switching the commenting on the + ** REP_ defines at the beginning of this source file. + */ + for (bi = 0; bi < boxes; ++bi) { + /* REP_AVERAGE_PIXELS version */ + + register int indx = bv[bi].ind; + register int clrs = bv[bi].colors; + register long r = 0, g = 0, b = 0, sum = 0; + + for (i = 0; i < clrs; ++i) { + r += PPM_GETR (chv[indx + i].color) * chv[indx + i].value; + g += PPM_GETG (chv[indx + i].color) * chv[indx + i].value; + b += PPM_GETB (chv[indx + i].color) * chv[indx + i].value; + sum += chv[indx + i].value; + } + r = r / sum; + if (r > maxval) + r = maxval; /* avoid math errors */ + g = g / sum; + if (g > maxval) + g = maxval; + b = b / sum; + if (b > maxval) + b = maxval; + PPM_ASSIGN (colormap[bi].color, r, g, b) ; + } + + /* All done. */ + return colormap; +} + + +static int +redCompare (ch1, ch2) +colorhist_vector ch1, ch2; +{ + return (int) PPM_GETR (ch1->color) - (int) PPM_GETR (ch2->color) ; +} + + +static int +greenCompare (ch1, ch2) +colorhist_vector ch1, ch2; +{ + return (int) PPM_GETG (ch1->color) - (int) PPM_GETG (ch2->color) ; +} + + +static int +blueCompare (ch1, ch2) +colorhist_vector ch1, ch2; +{ + return (int) PPM_GETB (ch1->color) - (int) PPM_GETB (ch2->color) ; +} + + +static int +sumCompare (b1, b2) +box_vector b1, b2; +{ + return b2->sum - b1->sum; +} + + +static colorhist_vector +computeColorHist (pixels, cols, rows, maxcolors, colorsP) +pixel**pixels; +int cols, rows, maxcolors; +int*colorsP; +{ + colorhash_table cht; + colorhist_vector chv; + + cht = computeColorHash (pixels, cols, rows, maxcolors, colorsP) ; + if (cht == (colorhash_table) 0) + return (colorhist_vector) 0; + chv = colorHashToColorHist (cht, maxcolors) ; + freeColorHash (cht) ; + return chv; +} + + +static void +addToColorHist (chv, colorsP, maxcolors, colorP, value, position) +colorhist_vector chv; +pixel*colorP; +int*colorsP; +int maxcolors, value, position; +{ + int i, j; + + /* Search colorhist for the color. */ + for (i = 0; i < *colorsP; ++i) + if (PPM_EQUAL (chv[i].color, *colorP) ) { + /* Found it - move to new slot. */ + if (position > i) { + for (j = i; j < position; ++j) + chv[j] = chv[j + 1]; + } else if (position < i) { + for (j = i; j > position; --j) + chv[j] = chv[j - 1]; + } + chv[position].color = *colorP; + chv[position].value = value; + return; + } + if (*colorsP < maxcolors) { + /* Didn't find it, but there's room to add it; so do so. */ + for (i = *colorsP; i > position; --i) + chv[i] = chv[i - 1]; + chv[position].color = *colorP; + chv[position].value = value; + ++(*colorsP); + } +} + + +static colorhash_table +computeColorHash (pixels, cols, rows, maxcolors, colorsP) +pixel**pixels; +int cols, rows, maxcolors; +int*colorsP; +{ + colorhash_table cht; + register pixel*pP; + colorhist_list chl; + int col, row, hash; + + cht = allocColorHash (); + *colorsP = 0; + + /* Go through the entire image, building a hash table of colors. */ + for (row = 0; row < rows; ++row) + for (col = 0, pP = pixels[row]; col < cols; ++col, ++pP) { + hash = hashPixel (*pP) ; + for (chl=cht[hash]; chl != (colorhist_list) 0; chl=chl->next) + if (PPM_EQUAL (chl->ch.color, *pP) ) + break; + if (chl != (colorhist_list) 0) + ++(chl->ch.value); + else + { + if (++(*colorsP) > maxcolors) { + freeColorHash (cht) ; + return (colorhash_table) 0; + } + chl = (colorhist_list) + malloc (sizeof(struct colorhist_list_item)); + if (chl == 0) + perror ("out of memory computing hash table") ; + chl->ch.color = *pP; + chl->ch.value = 1; + chl->next = cht[hash]; + cht[hash] = chl; + } + } + + return cht; +} + + +static colorhash_table +allocColorHash () +{ + colorhash_table cht; + int i; + + cht = (colorhash_table) malloc (HASH_SIZE * sizeof(colorhist_list)) ; + if (cht == 0) + perror ("out of memory allocating hash table") ; + + for (i = 0; i < HASH_SIZE; ++i) + cht[i] = (colorhist_list) 0; + + return cht; +} + + +static int +addToColorHash (cht, colorP, value) +colorhash_table cht; +pixel*colorP; +int value; +{ + register int hash; + register colorhist_list chl; + + chl = (colorhist_list) malloc (sizeof(struct colorhist_list_item) ) ; + if (chl == 0) + return - 1; + hash = hashPixel (*colorP) ; + chl->ch.color = *colorP; + chl->ch.value = value; + chl->next = cht[hash]; + cht[hash] = chl; + return 0; +} + + +static colorhist_vector +colorHashToColorHist (cht, maxcolors) +colorhash_table cht; +int maxcolors; +{ + colorhist_vector chv; + colorhist_list chl; + int i, j; + + /* Now collate the hash table into a simple colorhist array. */ + chv = (colorhist_vector) malloc (maxcolors * sizeof(struct colorhist_item) ) ; + /* (Leave room for expansion by caller.) */ + if (chv == (colorhist_vector) 0) + perror ("out of memory generating histogram") ; + + /* Loop through the hash table. */ + j = 0; + for (i = 0; i < HASH_SIZE; ++i) + for (chl = cht[i]; chl != (colorhist_list) 0; chl = chl->next) { + /* Add the new entry. */ + chv[j] = chl->ch; + ++j; + } + + /* All done. */ + return chv; +} + + +static colorhash_table +colorHistToColorHash (chv, colors) +colorhist_vector chv; +int colors; +{ + colorhash_table cht; + int i, hash; + pixel color; + colorhist_list chl; + + cht = allocColorHash (); + + for (i = 0; i < colors; ++i) { + color = chv[i].color; + hash = hashPixel (color) ; + for (chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next) +/* + if (PPM_EQUAL (chl->ch.color, color) ) + pm_error( + "same color found twice - %d %d %d", PPM_GETR(color), + PPM_GETG(color), PPM_GETB(color)) ; +*/ + chl = (colorhist_list) malloc (sizeof(struct colorhist_list_item) ) ; + if (chl == (colorhist_list) 0) + perror ("out of memory") ; + chl->ch.color = color; + chl->ch.value = i; + chl->next = cht[hash]; + cht[hash] = chl; + } + + return cht; +} + + +static int +lookupColor (cht, colorP) +colorhash_table cht; +pixel*colorP; +{ + int hash; + colorhist_list chl; + + hash = hashPixel (*colorP) ; + for (chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next) + if (PPM_EQUAL (chl->ch.color, *colorP) ) + return chl->ch.value; + + return - 1; +} + + +static void +freeColorHist (chv) +colorhist_vector chv; +{ + free ((char *) chv) ; +} + + +static void +freeColorHash (cht) +colorhash_table cht; +{ + int i; + colorhist_list chl, chlnext; + + for (i = 0; i < HASH_SIZE; ++i) + for (chl = cht[i]; chl != (colorhist_list) 0; chl = chlnext) { + chlnext = chl->next; + free ((char *) chl) ; + } + free ((char *) cht) ; +} |