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

  1. /* dither.c
  2.  *
  3.  * completely reworked dithering module for xloadimage
  4.  * uses error-diffusion dithering (floyd-steinberg) instead
  5.  * of simple 4x4 ordered-dither that was previously used
  6.  *
  7.  * the previous version of this code was written by steve losen
  8.  * (scl@virginia.edu)
  9.  * 
  10.  * jim frost    07.10.89
  11.  * Steve Losen  11.17.89
  12.  * kirk johnson 06.04.90
  13.  *
  14.  * Copyright 1990 Kirk L. Johnson (see the included file
  15.  * "kljcpyrght.h" for complete copyright information)
  16.  *
  17.  * Copyright 1989, 1990 Jim Frost and Steve Losen.
  18.  * See included file "copyright.h" for complete copyright information.
  19.  */
  20.  
  21. #include "copyright.h"
  22. #include "kljcpyrght.h"
  23. #include "image.h"
  24.  
  25. #define MaxIntensity  65536    /* maximum possible Intensity */
  26.  
  27. #define MaxGrey       32768    /* limits on the grey levels used */
  28. #define Threshold     16384    /* in the dithering process */
  29. #define MinGrey           0
  30.  
  31. static unsigned int tone_scale_adjust();
  32. static void         LeftToRight();
  33. static void         RightToLeft();
  34.  
  35. /*
  36.  * simple floyd-steinberg dither with serpentine raster processing
  37.  */
  38.  
  39. Image *dither(cimage, verbose)
  40.      Image        *cimage;
  41.      unsigned int  verbose;
  42. {
  43.   Image          *image;    /* destination image */
  44.   unsigned int   *grey;        /* grey map for source image */
  45.   unsigned int    spl;        /* source pixel length in bytes */
  46.   unsigned int    dll;        /* destination line length in bytes */
  47.   unsigned char  *src;        /* source data */
  48.   unsigned char  *dst;        /* destination data */
  49.   int            *curr;        /* current line buffer */
  50.   int            *next;        /* next line buffer */
  51.   int            *swap;        /* for swapping line buffers */
  52.   Pixel           color;    /* pixel color */
  53.   unsigned int    level;    /* grey level */
  54.   unsigned int    i, j;        /* loop counters */
  55.  
  56.   /*
  57.    * check the source image
  58.    */
  59.   goodImage(cimage, "dither");
  60.   if (BITMAPP(cimage))
  61.     return(NULL);
  62.  
  63.   /*
  64.    * allocate destination image
  65.    */
  66.   if (verbose)
  67.   {
  68.     printf("  Dithering image...");
  69.     fflush(stdout);
  70.   }
  71.   image = newBitImage(cimage->width, cimage->height);
  72.   if (cimage->title)
  73.   {
  74.     image->title = (char *)lmalloc(strlen(cimage->title) + 12);
  75.     sprintf(image->title, "%s (dithered)", cimage->title);
  76.   }
  77.  
  78.   /*
  79.    * if the number of entries in the colormap isn't too large, compute
  80.    * the grey level for each entry and store it in grey[]. else the
  81.    * grey levels will be computed on the fly.
  82.    */
  83.   if (RGBP(cimage) && (cimage->depth <= 16))
  84.   {
  85.     grey = (unsigned int *)lmalloc(sizeof(unsigned int) * cimage->rgb.used);
  86.     for (i=0; i<cimage->rgb.used; i++)
  87.       grey[i]=
  88.     (colorIntensity(cimage->rgb.red[i],
  89.             cimage->rgb.green[i],
  90.             cimage->rgb.blue[i]) >> 1);
  91.  
  92.     for (i=0; i<cimage->rgb.used; i++)
  93.       grey[i] = tone_scale_adjust(grey[i]);
  94.   }
  95.   else
  96.   {
  97.     grey = NULL;
  98.   }
  99.  
  100.   /*
  101.    * dither setup
  102.    */
  103.   spl = cimage->pixlen;
  104.   dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
  105.   src = cimage->data;
  106.   dst = image->data;
  107.  
  108.   curr  = (int *)lmalloc(sizeof(int) * (cimage->width + 2));
  109.   next  = (int *)lmalloc(sizeof(int) * (cimage->width + 2));
  110.   curr += 1;
  111.   next += 1;
  112.   for (j=0; j<cimage->width; j++)
  113.   {
  114.     curr[j] = 0;
  115.     next[j] = 0;
  116.   }
  117.  
  118.   /*
  119.    * primary dither loop
  120.    */
  121.   for (i=0; i<cimage->height; i++)
  122.   {
  123.     /* copy the row into the current line */
  124.     for (j=0; j<cimage->width; j++)
  125.     {
  126.       color = memToVal(src, spl);
  127.       src  += spl;
  128.       
  129.       if (RGBP(cimage)) {
  130.     if (grey == NULL)
  131.       level =
  132.         tone_scale_adjust(colorIntensity(cimage->rgb.red[color],
  133.                          cimage->rgb.green[color],
  134.                          cimage->rgb.blue[color]) >> 1);
  135.     else
  136.       level = grey[color];
  137.       }
  138.       else {
  139.     level =
  140.       tone_scale_adjust(colorIntensity((TRUE_RED(color) << 8),
  141.                        (TRUE_GREEN(color) << 8),
  142.                        (TRUE_BLUE(color) << 8)) >> 1);
  143.       }
  144.       curr[j] += level;
  145.     }
  146.  
  147.     /* dither the current line */
  148.     if (i & 0x01)
  149.       RightToLeft(curr, next, cimage->width);
  150.     else
  151.       LeftToRight(curr, next, cimage->width);
  152.  
  153.     /* copy the dithered line to the destination image */
  154.     for (j=0; j<cimage->width; j++)
  155.       if (curr[j] < Threshold)
  156.     dst[j / 8] |= 1 << (7 - (j & 7));
  157.     dst += dll;
  158.     
  159.     /* circulate the line buffers */
  160.     swap = curr;
  161.     curr = next;
  162.     next = swap;
  163.     for (j=0; j<cimage->width; j++)
  164.       next[j] = 0;
  165.   }
  166.  
  167.   /*
  168.    * clean up
  169.    */
  170.   if (grey)
  171.     lfree((byte *)grey);
  172.   lfree((byte *)(curr-1));
  173.   lfree((byte *)(next-1));
  174.   if (verbose)
  175.     printf("done\n");
  176.   
  177.   return(image);
  178. }
  179.  
  180.  
  181. /*
  182.  * a _very_ simple tone scale adjustment routine. provides a piecewise
  183.  * linear mapping according to the following:
  184.  *
  185.  *      input:          output:
  186.  *     0 (MinGrey)    0 (MinGrey)
  187.  *     Threshold      Threshold/2
  188.  *     MaxGrey        MaxGrey
  189.  * 
  190.  * this should help things look a bit better on most displays.
  191.  */
  192. static unsigned int tone_scale_adjust(val)
  193.      unsigned int val;
  194. {
  195.   unsigned int rslt;
  196.   
  197.   if (val < Threshold)
  198.     rslt = val / 2;
  199.   else
  200.     rslt = (((val - Threshold) * (MaxGrey-(Threshold/2))) /
  201.         (MaxGrey-Threshold)) + (Threshold/2);
  202.  
  203.   return rslt;
  204. }
  205.  
  206.  
  207. /*
  208.  * dither a line from left to right
  209.  */
  210. static void LeftToRight(curr, next, width)
  211.      int *curr;
  212.      int *next;
  213.      int  width;
  214. {
  215.   int idx;
  216.   int error;
  217.   int output;
  218.  
  219.   for (idx=0; idx<width; idx++)
  220.   {
  221.     output       = (curr[idx] > Threshold) ? MaxGrey : MinGrey;
  222.     error        = curr[idx] - output;
  223.     curr[idx]    = output;
  224.     next[idx-1] += error * 3 / 16;
  225.     next[idx]   += error * 5 / 16;
  226.     next[idx+1] += error * 1 / 16;
  227.     curr[idx+1] += error * 7 / 16;
  228.   }
  229. }
  230.  
  231.  
  232. /*
  233.  * dither a line from right to left
  234.  */
  235. static void RightToLeft(curr, next, width)
  236.      int *curr;
  237.      int *next;
  238.      int  width;
  239. {
  240.   int idx;
  241.   int error;
  242.   int output;
  243.  
  244.   for (idx=(width-1); idx>=0; idx--)
  245.   {
  246.     output       = (curr[idx] > Threshold) ? MaxGrey : MinGrey;
  247.     error        = curr[idx] - output;
  248.     curr[idx]    = output;
  249.     next[idx+1] += error * 3 / 16;
  250.     next[idx]   += error * 5 / 16;
  251.     next[idx-1] += error * 1 / 16;
  252.     curr[idx-1] += error * 7 / 16;
  253.   }
  254. }
  255.