/*---------------------------------------------------------------------------- pamchannel ------------------------------------------------------------------------------ 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" #include "shhopt.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. */ const char *input_filespec; /* Filespecs of input files */ const char *tupletype; /* Tuple type for output PAM */ 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. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); /* Instructions to optParseOptions3 on how to parse our options. */ optStruct3 opt; extern struct pam pam; /* Just so we can look at field sizes */ unsigned int option_def_index; unsigned int infileSpec, tupletypeSpec; option_def_index = 0; /* incremented by OPTENTRY */ OPTENT3(0, "infile", OPT_STRING, &cmdlineP->input_filespec, &infileSpec, 0); OPTENT3(0, "tupletype", OPT_STRING, &cmdlineP->tupletype, &tupletypeSpec, 0); 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 */ optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!infileSpec) cmdlineP->input_filespec = "-"; if (!tupletypeSpec) cmdlineP->tupletype = ""; else if (strlen(cmdlineP->tupletype)+1 > sizeof(pam.tuple_type)) pm_error("Tuple type name specified is too long. Maximum of " "%u characters allowed.", sizeof(pam.tuple_type)); cmdlineP->n_channel = 0; /* initial value */ { 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(int const n_channel, unsigned int const channels[], int const 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; strcpy(outpam.tuple_type, cmdline.tupletype); 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); }