/*---------------------------------------------------------------------------- pamtopnm ------------------------------------------------------------------------------ Part of the Netpbm package. Extract specified channels (planes) from a PAM image By Bryan Henderson, San Jose CA 2000.08.05 Contributed to the public domain by its author 2000.08.05. -----------------------------------------------------------------------------*/ #include "pam.h" #define MAX_CHANNELS 16 /* The most channels we allow user to specify */ 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 n_channel; /* The number of channels to extract. At least 1, at most 16. */ unsigned int channel_to_extract[MAX_CHANNELS]; /* The channel numbers to extract, in order. */ }; static void parse_command_line(int argc, char ** argv, struct cmdline_info *cmdlineP) { /*---------------------------------------------------------------------------- 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; option_def_index = 0; /* incremented by OPTENTRY */ OPTENTRY(0, "infile", OPT_STRING, &cmdlineP->input_filespec, 0); /* Set the defaults */ cmdlineP->input_filespec = "-"; 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. */ cmdlineP->n_channel = 0; { int argn; for (argn = 1; argn < argc; argn++) { int n; char *endptr; if (cmdlineP->n_channel >= MAX_CHANNELS) pm_error("You may not specify more than %d channels.", MAX_CHANNELS); n = strtol(argv[argn], &endptr, 10); if (n < 0) pm_error("Channel numbers cannot be negative. " "You specified %d", n); if (endptr == NULL) pm_error("non-numeric channel number argument: '%s'", argv[argn]); cmdlineP->channel_to_extract[cmdlineP->n_channel++] = n; } } if (cmdlineP->n_channel < 1) pm_error("You must specify at least one channel to extract."); } static void validate_channels(const int n_channel, const unsigned int channels[], const int depth) { int i; for (i = 0; i < n_channel; i++) if (channels[i] > depth-1) pm_error("You specified channel number %d. The highest numbered\n" "channel in the input image is %d.", channels[i], depth-1); } int main(int argc, char *argv[]) { struct cmdline_info cmdline; FILE* ifp; struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ pnm_init(&argc, argv); parse_command_line(argc, argv, &cmdline); ifp = pm_openr(cmdline.input_filespec); pnm_readpaminit(ifp, &inpam, sizeof(inpam)); validate_channels(cmdline.n_channel, cmdline.channel_to_extract, inpam.depth); outpam = inpam; /* Initial value */ outpam.file = stdout; outpam.depth = cmdline.n_channel; outpam.format = PAM_FORMAT; outpam.tuple_type[0] = '\0'; pnm_writepaminit(&outpam); { tuple *inrow; tuple *outrow; inrow = pnm_allocpamrow(&inpam); outrow = pnm_allocpamrow(&outpam); { int row; for (row = 0; row < inpam.height; row++) { int col; pnm_readpamrow(&inpam, inrow); for (col = 0; col < inpam.width; col ++) { int sample; for (sample = 0; sample < cmdline.n_channel; sample++) outrow[col][sample] = inrow[col][cmdline.channel_to_extract[sample]]; } pnm_writepamrow(&outpam, outrow); } } pnm_freepamrow(outrow); pnm_freepamrow(inrow); } exit(0); }