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

  1. #include "ppm.h"
  2. #include "ppmcmap.h"
  3.  
  4.  
  5. /*
  6.  * Yep, it's a very simple algorithm, but it was something I wanted to have
  7.  * available.
  8.  */
  9.  
  10. struct colorToGrayEntry {
  11.     pixel           color;
  12.     gray            gray;
  13.     int             frequency;
  14. };
  15.  
  16. /*
  17.  * BUG: This number was chosen pretty arbitrarily.  The program is * probably
  18.  * only useful for a very small numbers of colors - and that's * not only
  19.  * because of the O(n) search that's used.  The idea lends * itself primarily
  20.  * to low color (read: simple, machine generated) images.
  21.  */
  22. #define MAXCOLORS 255
  23.  
  24.  
  25. int main ARGS((int argc, char *argv[]));
  26. gray newGrayValue ARGS((pixel * pix, struct colorToGrayEntry * colorToGrayMap, int colors));
  27. int cmpColorToGrayEntryByIntensity ARGS((void *entry1, void *entry2));
  28. int cmpColorToGrayEntryByFrequency ARGS((void *entry1, void *entry2));
  29.  
  30.  
  31. int
  32. main(argc, argv)
  33.     int argc;
  34.     char *argv[];
  35. {
  36.     FILE           *ifp;
  37.     int             col, cols, row, rows, color, colors, argn;
  38.     int             frequency;
  39.     pixval          maxval;
  40.     pixel         **pixels;
  41.     pixel          *pP;
  42.     colorhist_vector hist;
  43.     gray           *grayrow;
  44.     gray           *gP;
  45.     struct colorToGrayEntry *colorToGrayMap;
  46.  
  47.  
  48.     ppm_init(&argc, argv);
  49.  
  50.     argn = 1;
  51.     /* Default is to sort colors by intensity */
  52.     frequency = 0;
  53.  
  54.     while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  55.     if (pm_keymatch(argv[argn], "-frequency", 2))
  56.         frequency = 1;
  57.     else if (pm_keymatch(argv[argn], "-intensity", 2))
  58.         frequency = 0;
  59.     else
  60.         pm_usage( "[-frequency|-intensity] [ppmfile]" );
  61.     ++argn;
  62.     }
  63.  
  64.     if (argn < argc) {
  65.     ifp = pm_openr(argv[argn]);
  66.     ++argn;
  67.     } else
  68.     ifp = stdin;
  69.  
  70.     pixels = ppm_readppm(ifp, &cols, &rows, &maxval);
  71.     pm_close(ifp);
  72.     /* all done with the input file - it's entirely in memory */
  73.  
  74.     /*
  75.      * Compute a histogram of the colors in the input.  This is good for
  76.      * both frequency, and indirectly the intensity, of a color.
  77.      */
  78.     hist = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
  79.  
  80.     if (hist == (colorhist_vector) 0)
  81.     /*
  82.      * BUG: This perhaps should use an exponential backoff, in
  83.      * the number of colors, until success - cf ppmquant's
  84.      * approach.  The results are then more what's expected, but
  85.      * not necessarily very useful.
  86.      */
  87.     pm_error("Too many colors - Try reducing with ppmquant");
  88.  
  89.     /* copy the colors into another structure for sorting */
  90.     colorToGrayMap = (struct colorToGrayEntry *)
  91.     malloc(sizeof(struct colorToGrayEntry) * colors);
  92.     for (color = 0; color < colors; color++) {
  93.     colorToGrayMap[color].color = hist[color].color;
  94.     colorToGrayMap[color].frequency = hist[color].value;
  95.     /*
  96.      * This next is derivable, of course, but it's far faster to
  97.      * store it precomputed.  This can be skipped, when sorting
  98.      * by frequency - but again, for a small number of colors
  99.      * it's a small matter.
  100.      */
  101.     colorToGrayMap[color].gray = PPM_LUMIN(hist[color].color);
  102.     }
  103.  
  104.     /*
  105.      * sort by intensity - sorting by frequency (in the histogram) is
  106.      * worth considering as a future addition.
  107.      */
  108.     if (frequency)
  109.     qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
  110.           cmpColorToGrayEntryByFrequency);
  111.     else
  112.     qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
  113.           cmpColorToGrayEntryByIntensity);
  114.  
  115.     /*
  116.      * create mapping between the n colors in input, to n evenly spaced
  117.      * grey-scale intensities.  This is done by overwriting the neatly
  118.      * formed gray values corresponding to the input-colors, with a new
  119.      * set of evenly spaced gray values.  Since maxval can be changed on
  120.      * a lark, we just use gray levels 0..colors-1, and adjust maxval
  121.      * accordingly
  122.      */
  123.     maxval = colors - 1;
  124.     for (color = 0; color < colors; color++)
  125.     colorToGrayMap[color].gray = color;
  126.  
  127.     /* write pgm file, mapping colors to intensities */
  128.     pgm_writepgminit(stdout, cols, rows, maxval, 0);
  129.  
  130.     grayrow = pgm_allocrow(cols);
  131.  
  132.     for (row = 0; row < rows; row++) {
  133.     for (col = 0, pP = pixels[row], gP = grayrow; col < cols;
  134.          col++, pP++, gP++)
  135.         *gP = newGrayValue(pP, colorToGrayMap, colors);
  136.     pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
  137.     }
  138.  
  139.     pm_close(stdout);
  140.  
  141.     exit(0);
  142. }
  143.  
  144. gray
  145. newGrayValue(pix, colorToGrayMap, colors)
  146.     pixel *pix;
  147.     struct colorToGrayEntry *colorToGrayMap;
  148.     int colors;
  149. {
  150.     int color;
  151.     /*
  152.      * Allowing this to be O(n), since the program is intended for small
  153.      * n.  Later, perhaps sort by color (r, then g, then b) and bsearch.
  154.      */
  155.     for (color = 0; color < colors; color++) {
  156.     if (PPM_EQUAL(*pix, colorToGrayMap[color].color))
  157.         return colorToGrayMap[color].gray;
  158.     }
  159.     pm_error("This should never happen - contact the maintainer");
  160. }
  161.  
  162. int
  163. cmpColorToGrayEntryByIntensity(entry1, entry2)
  164.     void *entry1, *entry2;
  165. {
  166.     return ((struct colorToGrayEntry *) entry1)->gray -
  167.     ((struct colorToGrayEntry *) entry2)->gray;
  168. }
  169.  
  170. int
  171. cmpColorToGrayEntryByFrequency(entry1, entry2)
  172.     void *entry1, *entry2;
  173. {
  174.     return ((struct colorToGrayEntry *) entry1)->frequency -
  175.     ((struct colorToGrayEntry *) entry2)->frequency;
  176. }
  177.