home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / ppm / ppmdither.c < prev    next >
C/C++ Source or Header  |  1993-10-04  |  7KB  |  263 lines

  1. /* ppmdither.c - Ordered dithering of a color ppm file to a specified number
  2. **               of primary shades.
  3. **
  4. ** Copyright (C) 1991 by Christos Zoulas.
  5. **
  6. ** Permission to use, copy, modify, and distribute this software and its
  7. ** documentation for any purpose and without fee is hereby granted, provided
  8. ** that the above copyright notice appear in all copies and that both that
  9. ** copyright notice and this permission notice appear in supporting
  10. ** documentation.  This software is provided "as is" without express or
  11. ** implied warranty.
  12. */
  13.  
  14. #include "ppm.h"
  15.  
  16. #define NC 256            /* Total number of colors        */
  17. #define NS 256            /* Max number of shades in primary    */
  18.  
  19. typedef unsigned char ubyte;
  20.  
  21. static int dith_nr  =   5;    /* number of red shades            */
  22. static int dith_ng  =   9;    /* number of green shades        */
  23. static int dith_nb  =   5;    /* number of blue shades        */
  24. static int dith_nc  = 225;    /* total number of colors 5 x 9 x 5    */
  25. static int dith_dim =   4;    /* dimension of the dither matrix    */
  26. static int dith_dm2 =  16;    /* dim square                */
  27. static int **dith_mat;         /* the dithering matrix            */
  28.  
  29. /* prototypes */
  30. static int dith_value ARGS((int y, int x, int size));
  31. static void dith_matrix ARGS((int dim));
  32. void dith_setup ARGS((int dim, int nr, int ng, int nb, pixel *ptab));
  33. int dith_color ARGS((float r, float g, float b));
  34. void dith_dither ARGS((int w, int h, register pixel *t, register pixel *i, register pixel *o));
  35. /* COLOR():
  36.  *    returns the index in the color table for the
  37.  *      r, g, b values specified.
  38.  */
  39. #define COLOR(r,g,b) (((r) * dith_ng + (g)) * dith_nb + (b))
  40.  
  41. /* LEVELS():
  42.  *    Returns the total number of levels after dithering.
  43.  */
  44. #define LEVELS(s)     (dith_dm2 * ((s) - 1) + 1)
  45.  
  46. /* DITHER():
  47.  *    Returns the dithered color for a single primary.
  48.  *      p = the input pixel
  49.  *      d = entry in the dither matrix
  50.  *      s = the number of levels of the primary
  51.  *
  52.  */
  53. #define DITHER(p,d,s) ((ubyte) ((LEVELS(s) * (p) + (d)) / (dith_dm2 * NS)))
  54.  
  55.  
  56. /* dith_value():
  57.  *    Return the value of a dither matrix of size x size at x, y 
  58.  *    [graphics gems, p. 714]
  59.  */
  60. static int
  61. dith_value(y, x, size)
  62. int y, x, size;
  63. {
  64.     register int d;
  65.  
  66.     /*
  67.      * Think of d as the density. At every iteration, d is shifted
  68.      * left one and a new bit is put in the low bit based on x and y.
  69.      * If x is odd and y is even, or visa versa, then a bit is shifted in.
  70.      * This generates the checkerboard pattern seen in dithering.
  71.      * This quantity is shifted again and the low bit of y is added in.
  72.      * This whole thing interleaves a checkerboard pattern and y's bits
  73.      * which is what you want.
  74.      */
  75.     for (d = 0; size-- > 0; x >>= 1, y >>= 1)
  76.     d = (d << 2) | (((x & 1) ^ (y & 1)) << 1) | (y & 1);
  77.     return(d);
  78. } /* end dith_value */
  79.  
  80.  
  81. /* dith_matrix():
  82.  *    Form the dithering matrix for the dimension specified
  83.  *    (Scaled by NS)
  84.  */
  85. static void
  86. dith_matrix(dim)
  87. int dim;
  88. {
  89.     int x, y, *dat;
  90.  
  91.     dith_dim = (1 << dim);
  92.     dith_dm2 = dith_dim * dith_dim;
  93.  
  94.     dith_mat = (int **) malloc((dith_dim * sizeof(int *)) + /* pointers */
  95.                    (dith_dm2 * sizeof(int)));   /* data */
  96.  
  97.     if (dith_mat == NULL) 
  98.     pm_error("out of memory");
  99.  
  100.     dat =  (int *) &dith_mat[dith_dim];
  101.     for (y = 0; y < dith_dim; y++)
  102.     dith_mat[y] = &dat[y * dith_dim];
  103.  
  104.     for (y = 0; y < dith_dim; y++) {
  105.     for (x = 0; x < dith_dim; x++) {
  106.          dith_mat[y][x] = NS * dith_value(y, x, dim);
  107. #ifdef DEBUG
  108.          (void) fprintf(stderr, "%4d ", dith_mat[y][x]);
  109. #endif
  110.     }
  111. #ifdef DEBUG
  112.     (void) fprintf(stderr, "\n");
  113. #endif
  114.     }
  115. } /* end dith_matrix */
  116.  
  117.     
  118. /* dith_setup():
  119.  *    Setup the dithering parameters, lookup table and dithering matrix
  120.  */
  121. void
  122. dith_setup(dim, nr, ng, nb, ptab)
  123. int dim, nr, ng, nb;
  124. pixel *ptab;
  125. {
  126.     register int r, g, b, i;
  127.  
  128.     dith_nr  = nr;
  129.     dith_ng  = ng;
  130.     dith_nb  = nb;
  131.     dith_nc  = nr * ng * nb;
  132.  
  133.     if (dith_nc > NC)
  134.     pm_error("too many shades %d, max %d", dith_nc, NC);
  135.     if (dith_nr < 2) 
  136.     pm_error("too few shades for red, minimum of 2");
  137.     if (dith_ng < 2) 
  138.     pm_error("too few shades for green, minimum of 2");
  139.     if (dith_nb < 2) 
  140.     pm_error("too few shades for blue, minimum of 2");
  141.     
  142.     for (r = 0; r < dith_nr; r++) 
  143.     for (g = 0; g < dith_ng; g++) 
  144.         for (b = 0; b < dith_nb; b++) {
  145.         i = COLOR(r,g,b);
  146.         PPM_ASSIGN(ptab[COLOR(r,g,b)], 
  147.                    (r * (NC-1) / (dith_nr - 1)),
  148.                    (g * (NC-1) / (dith_ng - 1)),
  149.                    (b * (NC-1) / (dith_nb - 1)));
  150.         }
  151.     
  152.     dith_matrix(dim);
  153. } /* end dith_setup */
  154.  
  155.  
  156. /* dith_color():
  157.  *  Return the closest color index for the one we ask
  158.  */
  159. int
  160. dith_color(r, g, b)
  161. float r, g, b;
  162. {
  163.     int rr, gg, bb;
  164.  
  165.     rr = r * (dith_nr - 1);
  166.     gg = g * (dith_ng - 1);
  167.     bb = b * (dith_nb - 1);
  168.     return((int) COLOR(rr, gg, bb));
  169. } /* end dith_color */
  170.  
  171.  
  172. /* dith_dither():
  173.  *  Dither height scanlines at a time
  174.  */
  175. void
  176. dith_dither(w, h, t, i, o)
  177. int w, h;
  178. register pixel *t;
  179. register pixel *i;
  180. register pixel *o;
  181. {
  182.     int y, dm = (dith_dim - 1);
  183.     register int x, d;
  184.     register int *m;
  185.  
  186.     for (y = 0; y < h; y++)
  187.     for (m = dith_mat[y & dm], x = w; --x >= 0;i++) {
  188.         d = m[x & dm];
  189.         *o++ = t[COLOR(DITHER(PPM_GETR(*i), d, dith_nr), 
  190.                    DITHER(PPM_GETG(*i), d, dith_ng), 
  191.                    DITHER(PPM_GETB(*i), d, dith_nb))];
  192.     }
  193. } /* end dith_dither */
  194.  
  195.  
  196. int
  197. main( argc, argv )
  198.     int argc;
  199.     char* argv[];
  200.     {
  201.     FILE* ifp;
  202.     pixel ptab[256];
  203.     pixel **ipixels, **opixels;
  204.     int cols, rows;
  205.     pixval maxval;
  206.     int argn;
  207.     char* usage = 
  208.     "[-dim <num>] [-red <num>] [-green <num>] [-blue <num>] [pbmfile]";
  209.  
  210.  
  211.     ppm_init( &argc, argv );
  212.  
  213.     argn = 1;
  214.  
  215.     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  216.     {
  217.     if ( pm_keymatch( argv[argn], "-dim", 1) &&  argn + 1 < argc ) {
  218.         argn++;
  219.         if (sscanf(argv[argn], "%d", &dith_dim) != 1)
  220.         pm_usage( usage );
  221.     }
  222.     else if ( pm_keymatch( argv[argn], "-red", 1 ) && argn + 1 < argc ) {
  223.         argn++;
  224.         if (sscanf(argv[argn], "%d", &dith_nr) != 1)
  225.         pm_usage( usage );
  226.     }
  227.     else if ( pm_keymatch( argv[argn], "-green", 1 ) && argn + 1 < argc ) {
  228.         argn++;
  229.         if (sscanf(argv[argn], "%d", &dith_ng) != 1)
  230.         pm_usage( usage );
  231.     }
  232.     else if ( pm_keymatch( argv[argn], "-blue", 1 ) && argn + 1 < argc ) {
  233.         argn++;
  234.         if (sscanf(argv[argn], "%d", &dith_nb) != 1)
  235.         pm_usage( usage );
  236.     }
  237.     else
  238.         pm_usage( usage );
  239.     ++argn;
  240.     }
  241.  
  242.     if ( argn != argc )
  243.     {
  244.     ifp = pm_openr( argv[argn] );
  245.     ++argn;
  246.     }
  247.     else
  248.     ifp = stdin;
  249.  
  250.     if ( argn != argc )
  251.     pm_usage( usage );
  252.  
  253.     ipixels = ppm_readppm( ifp, &cols, &rows, &maxval );
  254.     pm_close( ifp );
  255.     opixels = ppm_allocarray(cols, rows);
  256.     maxval = 255;
  257.     dith_setup(dith_dim, dith_nr, dith_ng, dith_nb, ptab);
  258.     dith_dither(cols, rows, ptab, &ipixels[0][0], &opixels[0][0]);
  259.     ppm_writeppm(stdout, opixels, cols, rows, maxval, 0);
  260.     pm_close(stdout);
  261.     exit(0);
  262. }
  263.