home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / xloadimg.zip / xloadimage.4.1 / compress.c < prev    next >
C/C++ Source or Header  |  1993-10-21  |  4KB  |  167 lines

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