home *** CD-ROM | disk | FTP | other *** search
- #include "ppm.h"
- #include "ppmcmap.h"
-
-
- /*
- * Yep, it's a very simple algorithm, but it was something I wanted to have
- * available.
- */
-
- struct colorToGrayEntry {
- pixel color;
- gray gray;
- int frequency;
- };
-
- /*
- * BUG: This number was chosen pretty arbitrarily. The program is * probably
- * only useful for a very small numbers of colors - and that's * not only
- * because of the O(n) search that's used. The idea lends * itself primarily
- * to low color (read: simple, machine generated) images.
- */
- #define MAXCOLORS 255
-
-
- int main ARGS((int argc, char *argv[]));
- gray newGrayValue ARGS((pixel * pix, struct colorToGrayEntry * colorToGrayMap, int colors));
- int cmpColorToGrayEntryByIntensity ARGS((void *entry1, void *entry2));
- int cmpColorToGrayEntryByFrequency ARGS((void *entry1, void *entry2));
-
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- FILE *ifp;
- int col, cols, row, rows, color, colors, argn;
- int frequency;
- pixval maxval;
- pixel **pixels;
- pixel *pP;
- colorhist_vector hist;
- gray *grayrow;
- gray *gP;
- struct colorToGrayEntry *colorToGrayMap;
-
-
- ppm_init(&argc, argv);
-
- argn = 1;
- /* Default is to sort colors by intensity */
- frequency = 0;
-
- while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
- if (pm_keymatch(argv[argn], "-frequency", 2))
- frequency = 1;
- else if (pm_keymatch(argv[argn], "-intensity", 2))
- frequency = 0;
- else
- pm_usage( "[-frequency|-intensity] [ppmfile]" );
- ++argn;
- }
-
- if (argn < argc) {
- ifp = pm_openr(argv[argn]);
- ++argn;
- } else
- ifp = stdin;
-
- pixels = ppm_readppm(ifp, &cols, &rows, &maxval);
- pm_close(ifp);
- /* all done with the input file - it's entirely in memory */
-
- /*
- * Compute a histogram of the colors in the input. This is good for
- * both frequency, and indirectly the intensity, of a color.
- */
- hist = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
-
- if (hist == (colorhist_vector) 0)
- /*
- * BUG: This perhaps should use an exponential backoff, in
- * the number of colors, until success - cf ppmquant's
- * approach. The results are then more what's expected, but
- * not necessarily very useful.
- */
- pm_error("Too many colors - Try reducing with ppmquant");
-
- /* copy the colors into another structure for sorting */
- colorToGrayMap = (struct colorToGrayEntry *)
- malloc(sizeof(struct colorToGrayEntry) * colors);
- for (color = 0; color < colors; color++) {
- colorToGrayMap[color].color = hist[color].color;
- colorToGrayMap[color].frequency = hist[color].value;
- /*
- * This next is derivable, of course, but it's far faster to
- * store it precomputed. This can be skipped, when sorting
- * by frequency - but again, for a small number of colors
- * it's a small matter.
- */
- colorToGrayMap[color].gray = PPM_LUMIN(hist[color].color);
- }
-
- /*
- * sort by intensity - sorting by frequency (in the histogram) is
- * worth considering as a future addition.
- */
- if (frequency)
- qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
- cmpColorToGrayEntryByFrequency);
- else
- qsort(colorToGrayMap, colors, sizeof(struct colorToGrayEntry),
- cmpColorToGrayEntryByIntensity);
-
- /*
- * create mapping between the n colors in input, to n evenly spaced
- * grey-scale intensities. This is done by overwriting the neatly
- * formed gray values corresponding to the input-colors, with a new
- * set of evenly spaced gray values. Since maxval can be changed on
- * a lark, we just use gray levels 0..colors-1, and adjust maxval
- * accordingly
- */
- maxval = colors - 1;
- for (color = 0; color < colors; color++)
- colorToGrayMap[color].gray = color;
-
- /* write pgm file, mapping colors to intensities */
- pgm_writepgminit(stdout, cols, rows, maxval, 0);
-
- grayrow = pgm_allocrow(cols);
-
- for (row = 0; row < rows; row++) {
- for (col = 0, pP = pixels[row], gP = grayrow; col < cols;
- col++, pP++, gP++)
- *gP = newGrayValue(pP, colorToGrayMap, colors);
- pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
- }
-
- pm_close(stdout);
-
- exit(0);
- }
-
- gray
- newGrayValue(pix, colorToGrayMap, colors)
- pixel *pix;
- struct colorToGrayEntry *colorToGrayMap;
- int colors;
- {
- int color;
- /*
- * Allowing this to be O(n), since the program is intended for small
- * n. Later, perhaps sort by color (r, then g, then b) and bsearch.
- */
- for (color = 0; color < colors; color++) {
- if (PPM_EQUAL(*pix, colorToGrayMap[color].color))
- return colorToGrayMap[color].gray;
- }
- pm_error("This should never happen - contact the maintainer");
- }
-
- int
- cmpColorToGrayEntryByIntensity(entry1, entry2)
- void *entry1, *entry2;
- {
- return ((struct colorToGrayEntry *) entry1)->gray -
- ((struct colorToGrayEntry *) entry2)->gray;
- }
-
- int
- cmpColorToGrayEntryByFrequency(entry1, entry2)
- void *entry1, *entry2;
- {
- return ((struct colorToGrayEntry *) entry1)->frequency -
- ((struct colorToGrayEntry *) entry2)->frequency;
- }
-