/*---------------------------------------------------------------------------- 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 #include "pm_c_util.h" #include "mallocvar.h" #include "shhopt.h" #include "pam.h" #define MAX_CHANNELS 16 /* The most channels we allow user to specify */ struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; /* Filename 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 parseCommandLine(int argc, const char ** argv, struct CmdlineInfo * const 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; optStruct3 opt; extern struct pam pam; /* Just so we can look at field sizes */ unsigned int option_def_index; unsigned int infileSpec, tupletypeSpec; MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "infile", OPT_STRING, &cmdlineP->inputFileName, &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 have no parms that are negative numbers */ pm_optParseOptions4(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!infileSpec) cmdlineP->inputFileName = "-"; 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.", (unsigned)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 validateChannels(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); } static void doOneImage(FILE * const ifP, FILE * const ofP, unsigned int const nChannel, unsigned int const channelToExtract[], const char * const tupletype) { struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); validateChannels(nChannel, channelToExtract, inpam.depth); outpam = inpam; /* Initial value */ outpam.file = ofP; outpam.depth = nChannel; outpam.format = PAM_FORMAT; strcpy(outpam.tuple_type, tupletype); pnm_writepaminit(&outpam); { tuple * inrow; tuple * outrow; inrow = pnm_allocpamrow(&inpam); outrow = pnm_allocpamrow(&outpam); { unsigned int row; for (row = 0; row < inpam.height; ++row) { unsigned int col; pnm_readpamrow(&inpam, inrow); for (col = 0; col < inpam.width; ++col) { unsigned int plane; for (plane = 0; plane < nChannel; ++plane) outrow[col][plane] = inrow[col][channelToExtract[plane]]; } pnm_writepamrow(&outpam, outrow); } } pnm_freepamrow(outrow); pnm_freepamrow(inrow); } } int main(int argc, const char *argv[]) { struct CmdlineInfo cmdline; FILE * ifP; int eof; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); eof = FALSE; while (!eof) { doOneImage(ifP, stdout, cmdline.n_channel, cmdline.channel_to_extract, cmdline.tupletype); pnm_nextimage(ifP, &eof); } pm_close(ifP); return 0; }