home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume5 / xldimage / part01 / dither.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-13  |  3.8 KB  |  133 lines

  1. /* dither.c:
  2.  *
  3.  * routine for dithering a color image to monochrome based on color
  4.  * intensity.  this is loosely based on an algorithm which barry shein
  5.  * (bzs@std.com) used in his "xf" program.
  6.  *
  7.  * jim frost 07.10.89
  8.  *
  9.  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
  10.  * copyright information.
  11.  */
  12.  
  13. #include "copyright.h"
  14. #include "image.h"
  15.  
  16. /* 4x4 arrays used for dithering, arranged by nybble
  17.  */
  18.  
  19. #define GRAYS    17 /* ((4 * 4) + 1) patterns for a good dither */
  20. #define GRAYSTEP ((unsigned long)(65536 * 3) / GRAYS)
  21.  
  22. static byte DitherBits[GRAYS][4] = {
  23.   0xf, 0xf, 0xf, 0xf,
  24.   0xe, 0xf, 0xf, 0xf,
  25.   0xe, 0xf, 0xb, 0xf,
  26.   0xa, 0xf, 0xb, 0xf,
  27.   0xa, 0xf, 0xa, 0xf,
  28.   0xa, 0xd, 0xa, 0xf,
  29.   0xa, 0xd, 0xa, 0x7,
  30.   0xa, 0x5, 0xa, 0x7,
  31.   0xa, 0x5, 0xa, 0x5,
  32.   0x8, 0x5, 0xa, 0x5,
  33.   0x8, 0x5, 0x2, 0x5,
  34.   0x0, 0x5, 0x2, 0x5,
  35.   0x0, 0x5, 0x0, 0x5,
  36.   0x0, 0x4, 0x0, 0x5,
  37.   0x0, 0x4, 0x0, 0x1,
  38.   0x0, 0x0, 0x0, 0x1,
  39.   0x0, 0x0, 0x0, 0x0
  40. };
  41.  
  42. /* simple dithering algorithm, really optimized for the 4x4 array
  43.  */
  44.  
  45. Image *dither(cimage, verbose)
  46.      Image        *cimage;
  47.      unsigned int  verbose;
  48. { Image         *image;
  49.   unsigned char *sp, *dp, *dp2; /* data pointers */
  50.   unsigned int   dindex;        /* index into dither array */
  51.   unsigned int   spl;           /* source pixel length in bytes */
  52.   unsigned int   dll;           /* destination line length in bytes */
  53.   Pixel          color;         /* pixel color */
  54.   unsigned int  *index;         /* index into dither array for a given pixel */
  55.   unsigned int   a, x, y;       /* random counters */
  56.  
  57.   goodImage(cimage, "dither");
  58.   if (! RGBP(cimage))
  59.     return(NULL);
  60.  
  61.   /* set up
  62.    */
  63.  
  64.   if (verbose) {
  65.     printf("  Dithering image...");
  66.     fflush(stdout);
  67.   }
  68.   image= newBitImage(cimage->width * 4, cimage->height * 4);
  69.   if (cimage->title) {
  70.     image->title= (char *)malloc(strlen(cimage->title) + 12);
  71.     sprintf(image->title, "%s (dithered)", cimage->title);
  72.   }
  73.   spl= cimage->pixlen;
  74.   dll= (image->width / 8) + (image->width % 8 ? 1 : 0);
  75.  
  76.   /* if the number of possible pixels isn't very large, build an array
  77.    * which we index by the pixel value to find the dither array index
  78.    * by color brightness.  we do this in advance so we don't have to do
  79.    * it for each pixel.  things will break if a pixel value is greater
  80.    * than (1 << depth), which is bogus anyway.  this calculation is done
  81.    * on a per-pixel basis if the colormap is too big.
  82.    */
  83.  
  84.   if (cimage->depth <= 16) {
  85.     index= (unsigned int *)malloc(sizeof(unsigned int) * cimage->rgb.used);
  86.     for (x= 0; x < cimage->rgb.used; x++)
  87.       *(index + x)=
  88.     ((unsigned long)(*(cimage->rgb.red + x)) +
  89.      *(cimage->rgb.green + x) +
  90.      *(cimage->rgb.blue + x)) / GRAYSTEP;
  91.   }
  92.   else
  93.     index= NULL;
  94.  
  95.   /* dither each pixel
  96.    */
  97.  
  98.   sp= cimage->data;
  99.   dp= image->data;
  100.   for (y= 0; y < cimage->height; y++) {
  101.     for (x= 0; x < cimage->width; x++) {
  102.       dp2= dp + (x >> 1);
  103.       color= memToVal(sp, spl);
  104.       if (index)
  105.     dindex= *(index + color);
  106.       else
  107.     dindex= ((unsigned long)(*(cimage->rgb.red + color)) +
  108.          *(cimage->rgb.green + color) +
  109.          *(cimage->rgb.blue + color)) / GRAYSTEP;
  110.  
  111.       /* loop for the four Y bits in the dither pattern, putting all
  112.        * four X bits in at once.  if you think this would be hard to
  113.        * change to be an NxN dithering array, you're right, since we're
  114.        * banking on the fact that we need only shift the mask based on
  115.        * whether x is odd or not.  an 8x8 array wouldn't even need that,
  116.        * but blowing an image up by 64x is probably not a feature.
  117.        */
  118.  
  119.       if (x & 1)
  120.     for (a= 0; a < 4; a++, dp2 += dll)
  121.       *dp2 |= DitherBits[dindex][a];
  122.       else
  123.     for (a= 0; a < 4; a++, dp2 += dll)
  124.       *dp2 |= (DitherBits[dindex][a] << 4);
  125.       sp += spl;
  126.     }
  127.     dp += (dll << 2); /* (dll * 4) but I like shifts */
  128.   }
  129.   if (verbose)
  130.     printf("done\n");
  131.   return(image);
  132. }
  133.