diff options
Diffstat (limited to 'other/pamstack.c')
-rw-r--r-- | other/pamstack.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/other/pamstack.c b/other/pamstack.c new file mode 100644 index 00000000..4f8d9945 --- /dev/null +++ b/other/pamstack.c @@ -0,0 +1,240 @@ +/*---------------------------------------------------------------------------- + pamstack +------------------------------------------------------------------------------ + Part of the Netpbm package. + + Combine the channels (stack the planes) of multiple PAM images to create + a single PAM image. + + + By Bryan Henderson, San Jose CA 2000.08.05 + + Contributed to the public domain by its author 2002.05.05. +-----------------------------------------------------------------------------*/ + +#include <string.h> + +#include "mallocvar.h" +#include "shhopt.h" +#include "pam.h" + +#define MAX_INPUTS 16 + /* The most input PAMs 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 *tupletype; /* Tuple type for output PAM */ + unsigned int nInput; + /* The number of input PAMs. At least 1, at most 16. */ + const char * inputFileName[MAX_INPUTS]; + /* The PAM files to combine, in order. */ +}; + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec strings we return are stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* 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 tupletypeSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + 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 (!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->nInput = 0; /* initial value */ + { + int argn; + for (argn = 1; argn < argc; argn++) { + if (cmdlineP->nInput >= MAX_INPUTS) + pm_error("You may not specify more than %d input images.", + MAX_INPUTS); + cmdlineP->inputFileName[cmdlineP->nInput++] = argv[argn]; + } + } + if (cmdlineP->nInput < 1) + pm_error("You must specify at least one input PAM image."); +} + + + +static void +openAllStreams(unsigned int const nInput, + const char ** const inputFileName, + FILE ** const ifP) { + + unsigned int inputSeq; + + for (inputSeq = 0; inputSeq < nInput; ++inputSeq) + ifP[inputSeq] = pm_openr(inputFileName[inputSeq]); +} + + + +static void +outputRaster(const struct pam inpam[], + unsigned int const nInput, + struct pam outpam) { + + tuple *inrow; + tuple *outrow; + + outrow = pnm_allocpamrow(&outpam); + inrow = pnm_allocpamrow(&outpam); + + { + int row; + + for (row = 0; row < outpam.height; row++) { + unsigned int inputSeq; + int outplane; + outplane = 0; /* initial value */ + for (inputSeq = 0; inputSeq < nInput; ++inputSeq) { + struct pam thisInpam = inpam[inputSeq]; + int col; + + pnm_readpamrow(&thisInpam, inrow); + + for (col = 0; col < outpam.width; col ++) { + int inplane; + for (inplane = 0; inplane < thisInpam.depth; ++inplane) + outrow[col][outplane+inplane] = inrow[col][inplane]; + } + outplane += thisInpam.depth; + } + pnm_writepamrow(&outpam, outrow); + } + } + pnm_freepamrow(outrow); + pnm_freepamrow(inrow); +} + + + +static void +processOneImageInAllStreams(unsigned int const nInput, + FILE * const ifP[], + FILE * const ofP, + const char * const tupletype) { + + struct pam inpam[MAX_INPUTS]; /* Input PAM images */ + struct pam outpam; /* Output PAM image */ + + unsigned int inputSeq; + /* The horizontal sequence -- i.e. the sequence of the + input stream, not the sequence of an image within a + stream. + */ + + unsigned int outputDepth; + outputDepth = 0; /* initial value */ + + for (inputSeq = 0; inputSeq < nInput; ++inputSeq) { + + pnm_readpaminit(ifP[inputSeq], &inpam[inputSeq], + PAM_STRUCT_SIZE(tuple_type)); + + if (inputSeq > 0) { + /* All images, including this one, must be compatible with the + first image. + */ + if (inpam[inputSeq].width != inpam[0].width) + pm_error("Image no. %u does not have the same width as " + "Image 0.", inputSeq); + if (inpam[inputSeq].height != inpam[0].height) + pm_error("Image no. %u does not have the same height as " + "Image 0.", inputSeq); + if (inpam[inputSeq].maxval != inpam[0].maxval) + pm_error("Image no. %u does not have the same maxval as " + "Image 0.", inputSeq); + } + outputDepth += inpam[inputSeq].depth; + } + + outpam = inpam[0]; /* Initial value */ + outpam.depth = outputDepth; + outpam.file = ofP; + outpam.format = PAM_FORMAT; + strcpy(outpam.tuple_type, tupletype); + + pm_message("Writing %u channel PAM image", outpam.depth); + + pnm_writepaminit(&outpam); + + outputRaster(inpam, nInput, outpam); +} + + + +static void +nextImageAllStreams(unsigned int const nInput, + FILE * const ifP[], + bool * const eofP) { +/*---------------------------------------------------------------------------- + Advance all the streams ifP[] to the next image. + + Return *eofP == TRUE iff at least one stream has no next image. +-----------------------------------------------------------------------------*/ + unsigned int inputSeq; + + for (inputSeq = 0; inputSeq < nInput; ++inputSeq) { + bool eof; + pnm_nextimage(ifP[inputSeq], &eof); + if (eof) + *eofP = eof; + } +} + + + +int +main(int argc, char *argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP[MAX_INPUTS]; + bool eof; + + pnm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + openAllStreams(cmdline.nInput, cmdline.inputFileName, ifP); + + eof = FALSE; + while (!eof) { + processOneImageInAllStreams(cmdline.nInput, ifP, stdout, + cmdline.tupletype); + + nextImageAllStreams(cmdline.nInput, ifP, &eof); + } + + return 0; +} |