/* pnmhistmap.c - * Draw a histogram for a PGM or PPM file * * Options: -verbose: the usual * -max N: force scaling value to N * -black: ignore all-black count * -white: ignore all-white count * * - PGM histogram is a PBM file, PPM histogram is a PPM file * - No conditional code - assumes all three: PBM, PGM, PPM * * Copyright (C) 1993 by Wilson H. Bent, Jr (whb@usc.edu) * */ #include #include "pnm.h" #define HIST_WIDTH 256 #define HIST_HEIGHT 200 static int rows, hist_cols; static xelval maxval; static int format; static int verbose = 0; static int no_black = 0; static int no_white = 0; static int rhist[HIST_WIDTH]; static int ghist[HIST_WIDTH]; static int bhist[HIST_WIDTH]; static int hmax = -1; static double scale; static void pgm_hist (FILE *fp) { gray *grayrow; bit **bits; int i, j; int start, finish; if ((bits = pbm_allocarray (HIST_WIDTH, HIST_HEIGHT)) == NULL) pm_error ("no space for output array (%d bits)", HIST_WIDTH * HIST_HEIGHT); memset (ghist, 0, sizeof (ghist)); /* read the pixel values into the histogram arrays */ grayrow = pgm_allocrow (hist_cols); /*XX error-check! */ if (verbose) pm_message ("making histogram..."); for (i = rows; i > 0; --i) { pgm_readpgmrow (fp, grayrow, hist_cols, maxval, format); for (j = hist_cols-1; j >= 0; --j) ghist[grayrow[j]]++; } pgm_freerow (grayrow); fclose (fp); /* find the highest-valued slot and set the scale value */ if (verbose) pm_message ("finding max. slot height..."); if (hmax == -1) { start = (no_black ? 1 : 0); finish = (no_white ? HIST_WIDTH - 1 : HIST_WIDTH); for (hmax = 0, i = start; i < finish; ++i) if (hmax < ghist[i]) hmax = ghist[i]; } for (i = 0; i < HIST_WIDTH; ++i) if (ghist[0] > hmax) ghist[0] = hmax; if (verbose) pm_message ("Done: height = %d", hmax); scale = (double) HIST_HEIGHT / hmax; for (i = 0; i < HIST_WIDTH; ++i) { int mark = HIST_HEIGHT - (int)(scale * ghist[i]); for (j = 0; j < mark; ++j) bits[j][i] = PBM_BLACK; for ( ; j < HIST_HEIGHT; ++j) bits[j][i] = PBM_WHITE; } pbm_writepbm (stdout, bits, HIST_WIDTH, HIST_HEIGHT, 0); } static void ppm_hist (FILE * fp) { pixel *pixrow; pixel **pixels; int i, j; int start, finish; if ((pixels = ppm_allocarray (HIST_WIDTH, HIST_HEIGHT)) == NULL) pm_error ("no space for output array (%d pixels)", HIST_WIDTH * HIST_HEIGHT); for (i = 0; i < HIST_HEIGHT; ++i) memset (pixels[i], 0, HIST_WIDTH * sizeof (pixel)); memset (rhist, 0, sizeof (rhist)); memset (ghist, 0, sizeof (ghist)); memset (bhist, 0, sizeof (bhist)); /* read the pixel values into the histogram arrays */ pixrow = ppm_allocrow (hist_cols); /*XX error-check! */ if (verbose) pm_message ("making histogram..."); for (i = rows; i > 0; --i) { ppm_readppmrow (fp, pixrow, hist_cols, maxval, format); for (j = hist_cols-1; j >= 0; --j) { rhist[PPM_GETR(pixrow[j])]++; ghist[PPM_GETG(pixrow[j])]++; bhist[PPM_GETB(pixrow[j])]++; } } ppm_freerow (pixrow); fclose (fp); /* find the highest-valued slot and set the scale value */ if (verbose) pm_message ("finding max. slot height..."); if (hmax == -1) { start = (no_black ? 1 : 0); finish = (no_white ? HIST_WIDTH - 1 : HIST_WIDTH); for (hmax = 0, i = start; i < finish; ++i) { if (hmax < rhist[i]) hmax = rhist[i]; if (hmax < ghist[i]) hmax = ghist[i]; if (hmax < bhist[i]) hmax = bhist[i]; } } for (i = 0; i < HIST_WIDTH; ++i) { if (rhist[i] > hmax) rhist[i] = hmax; if (ghist[i] > hmax) ghist[i] = hmax; if (bhist[i] > hmax) bhist[i] = hmax; } if (verbose) pm_message ("Done: height = %d", hmax); scale = (double) HIST_HEIGHT / hmax; for (i = 0; i < HIST_WIDTH; ++i) { for (j = HIST_HEIGHT - (int)(scale * rhist[i]); j < HIST_HEIGHT; ++j) PPM_PUTR(pixels[j][i], maxval); for (j = HIST_HEIGHT - (int)(scale * ghist[i]); j < HIST_HEIGHT; ++j) PPM_PUTG(pixels[j][i], maxval); for (j = HIST_HEIGHT - (int)(scale * bhist[i]); j < HIST_HEIGHT; ++j) PPM_PUTB(pixels[j][i], maxval); } ppm_writeppm (stdout, pixels, HIST_WIDTH, HIST_HEIGHT, maxval, 0); } int main (int argc, char ** argv) { FILE *ifp; int argn = 1; const char * const usage = "[-white] [-black] [-max maxvalue] [-verbose] [pnmfile]"; pnm_init (&argc, argv); /* Check for flags. */ while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch( argv[argn], "-white", 2 ) ) no_white = 1; else if ( pm_keymatch( argv[argn], "-black", 2 ) ) no_black = 1; else if ( pm_keymatch( argv[argn], "-max", 2 ) ) { if ((hmax = atoi (argv[++argn])) <= 0) pm_error ("Max. value (%d) must be positive", hmax); } else if ( pm_keymatch( argv[argn], "-verbose", 2 ) ) verbose = 1; else pm_usage( usage ); ++argn; } if (--argc > argn) pm_usage (usage); else if (argc == argn) ifp = pm_openr (argv[argn]); else ifp = stdin; pnm_readpnminit (ifp, &hist_cols, &rows, &maxval, &format); switch (PNM_FORMAT_TYPE (format)) { case PPM_TYPE: ppm_hist (ifp); break; case PGM_TYPE: pgm_hist (ifp); break; case PBM_TYPE: pm_error ("no histograms for PBM files"); break; } exit (0); }