/* ppmhist.c - read a portable pixmap and compute a color histogram ** ** Copyright (C) 1989 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "ppm.h" #include "ppmcmap.h" #define MAXCOLORS 100000 struct cmdline_info { /* All the information the user supplied in the command line, in a form easy for the program to use. */ char *input_filespec; /* Filespecs of input files */ int map; /* -map option */ int noheader; /* -noheader option */ int hexcolor; /* -hexcolor option */ }; static void parse_command_line(int argc, char ** argv, struct cmdline_info *cmdline_p) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ optStruct *option_def = malloc(100*sizeof(optStruct)); /* Instructions to OptParseOptions2 on how to parse our options. */ optStruct2 opt; unsigned int option_def_index; int nomap; /* dummy option for backward compatibility */ option_def_index = 0; /* incremented by OPTENTRY */ OPTENTRY(0, "map", OPT_FLAG, &cmdline_p->map, 0); OPTENTRY(0, "nomap", OPT_FLAG, &nomap, 0); OPTENTRY(0, "noheader", OPT_FLAG, &cmdline_p->noheader, 0); OPTENTRY(0, "hexcolor", OPT_FLAG, &cmdline_p->hexcolor, 0); /* Set the defaults */ cmdline_p->map = FALSE; cmdline_p->noheader = FALSE; cmdline_p->hexcolor = FALSE; opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ pm_optParseOptions2(&argc, argv, opt, 0); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (argc-1 == 0) cmdline_p->input_filespec = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " "specified %d", argc-1); else cmdline_p->input_filespec = argv[1]; if (cmdline_p->hexcolor && cmdline_p->map) pm_error("You cannot specify both -hexcolor and -map"); } static int countcompare(const void *ch1, const void *ch2) { return ((colorhist_vector)ch2)->value - ((colorhist_vector)ch1)->value; } int main(int argc, char *argv[] ) { struct cmdline_info cmdline; FILE* ifp; pixel** pixels; colorhist_vector chv; int rows, cols, colors, i; pixval maxval; ppm_init( &argc, argv ); parse_command_line(argc, argv, &cmdline); ifp = pm_openr(cmdline.input_filespec); pixels = ppm_readppm( ifp, &cols, &rows, &maxval ); pm_close( ifp ); chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors ); if ( chv == (colorhist_vector) 0 ) pm_error( "too many colors - try doing a ppmquant" ); /* Sort by count. */ qsort( (char*) chv, colors, sizeof(struct colorhist_item), countcompare ); /* And print the histogram. */ if (cmdline.map) printf("P3\n# color map\n%d 1\n%d\n", colors, maxval); if (!cmdline.noheader) { printf( "%c r g b \t lum \t count\n", cmdline.map ? '#' : ' '); printf( "%c----- ----- ----- \t-----\t-------\n", cmdline.map ? '#' : ' '); } for ( i = 0; i < colors; i++ ) { printf(cmdline.hexcolor ? " %04x %04x %04x%s\t%5d\t%7d\n" : " %5d %5d %5d%s\t%5d\t%7d\n", PPM_GETR(chv[i].color), PPM_GETG(chv[i].color), PPM_GETB(chv[i].color), (cmdline.map ? " #" : ""), (int) ( PPM_LUMIN( chv[i].color ) + 0.5 ), chv[i].value ); } ppm_freecolorhist( chv ); exit( 0 ); }