1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
/* compress.c:
*
* compress a colormap by removing unused or duplicate RGB colors. this
* uses a 15-bit true color pixel as an index into a hash table of pixel
* values (similar to the technique used in reduce.c).
*
* jim frost 10.05.89
*
* Copyright 1991 Jim Frost.
* See included file "copyright.h" for complete copyright information.
*/
#include "copyright.h"
#include "image.h"
/* this converts a TLA-style pixel into a 15-bit true color pixel
*/
#define TLA_TO_15BIT(TABLE,PIXEL) \
((((TABLE).red[PIXEL] & 0xf800) >> 1) | \
(((TABLE).green[PIXEL] & 0xf800) >> 6) | \
(((TABLE).blue[PIXEL] & 0xf800) >> 11))
/* these macros extract color intensities from a 15-bit true color pixel
*/
#define RED_INTENSITY(P) (((P) & 0x7c00) >> 10)
#define GREEN_INTENSITY(P) (((P) & 0x03e0) >> 5)
#define BLUE_INTENSITY(P) ((P) & 0x001f)
#define NIL_PIXEL 0xffffffff
void compress_cmap(image, verbose)
Image *image;
unsigned int verbose;
{ Pixel hash_table[32768];
Pixel *pixel_table;
Pixel *pixel_map;
Pixel index, oldpixval, newpixval;
byte *pixptr;
unsigned int x, y, badcount, dupcount;
RGBMap rgb;
goodImage(image, "compress");
if (!RGBP(image) || image->rgb.compressed) /* we're AT&T */
return;
if (verbose) {
printf(" Compressing colormap...");
fflush(stdout);
}
/* initialize hash table and allocate new RGB intensity tables
*/
for (x= 0; x < 32768; x++)
hash_table[x]= NIL_PIXEL;
newRGBMapData(&rgb, image->rgb.used);
rgb.size= image->rgb.used;
rgb.used= 0;
pixel_table= (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
pixel_map= (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
for (x= 0; x < image->rgb.used; x++)
pixel_map[x]= NIL_PIXEL;
pixptr= image->data;
dupcount= badcount= 0;
for (y= 0; y < image->height; y++)
for (x= 0; x < image->width; x++) {
oldpixval= memToVal(pixptr, image->pixlen);
if (oldpixval > image->rgb.used) {
badcount++;
oldpixval= 0;
}
/* if we don't already know what value the new pixel will have,
* look for a similar pixel in hash table.
*/
if (pixel_map[oldpixval] == NIL_PIXEL) {
index= TLA_TO_15BIT(image->rgb, oldpixval);
/* nothing similar
*/
if (hash_table[index] == NIL_PIXEL) {
newpixval= rgb.used++;
hash_table[index]= newpixval;
}
/* we've seen one like this before; try to find out if it's an
* exact match
*/
else {
newpixval= hash_table[index];
for (;;) {
/* if the color is the same as another color we've seen,
* use the pixel that the other color is using
*/
if ((rgb.red[newpixval] == image->rgb.red[oldpixval]) &&
(rgb.green[newpixval] == image->rgb.green[oldpixval]) &&
(rgb.blue[newpixval] == image->rgb.blue[oldpixval])) {
pixel_map[oldpixval]= newpixval; /* same color */
dupcount++;
goto move_pixel;
}
/* if we're at the end of the chain, we're the first pixel
* of this color
*/
if (pixel_table[newpixval] == NIL_PIXEL) /* end of the chain */
break;
newpixval= pixel_table[newpixval];
}
pixel_table[newpixval]= rgb.used;
newpixval= rgb.used++;
}
pixel_map[oldpixval]= newpixval;
pixel_table[newpixval]= NIL_PIXEL;
rgb.red[newpixval]= image->rgb.red[oldpixval];
rgb.green[newpixval]= image->rgb.green[oldpixval];
rgb.blue[newpixval]= image->rgb.blue[oldpixval];
}
/* change the pixel
*/
move_pixel:
valToMem(pixel_map[oldpixval], pixptr, image->pixlen);
pixptr += image->pixlen;
}
lfree((byte *)pixel_table);
lfree((byte *)pixel_map);
if (badcount) {
if (verbose)
printf("%d out-of-range pixels, ", badcount);
else
fprintf(stderr, "Warning: %d out-of-range pixels were seen\n",
badcount);
}
if (verbose) {
if ((rgb.used == image->rgb.used) && !badcount)
printf("no improvment\n");
else {
int unused= image->rgb.used - rgb.used - dupcount;
if (dupcount)
printf("%d duplicate%s and %d unused color%s removed...",
dupcount, (dupcount == 1 ? "" : "s"),
unused, (unused == 1 ? "" : "s"));
printf("%d unique color%s\n",
rgb.used, (rgb.used == 1 ? "" : "s"));
}
}
/* image is converted; now fix up its colormap
*/
freeRGBMapData(&(image->rgb));
image->rgb= rgb;
image->rgb.compressed= 1;
}
|