text: /*----------------------------------------------------------------------------
                                 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 "pam.h"
  #include "shhopt.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. */
      char * inputFilespec[MAX_INPUTS];
          /* The PAM files to combine, in order. */
  };
  
  
  
  static void
  parseCommandLine(int argc, char ** argv,
                   struct cmdlineInfo *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 = 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 tupletypeSpec;
  
      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->inputFilespec[cmdlineP->nInput++] = argv[argn];
          }
      }
      if (cmdlineP->nInput < 1)
          pm_error("You must specify at least one input PAM image.");
  }
  
  
  
  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);        
  }
  
  
  
  int
  main(int argc, char *argv[]) {
  
      struct cmdlineInfo cmdline;
      FILE* ifp[MAX_INPUTS];
      struct pam inpam[MAX_INPUTS];   /* Input PAM imageS */
      struct pam outpam;  /* Output PAM image */
      unsigned int inputSeq;
      int outputDepth;
  
      pnm_init(&argc, argv);
  
      parseCommandLine(argc, argv, &cmdline);
  
      outputDepth = 0;  /* initial value */
      
  
      for (inputSeq = 0; inputSeq < cmdline.nInput; ++inputSeq) {
  
          ifp[inputSeq] = pm_openr(cmdline.inputFilespec[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 = stdout;
      outpam.format = PAM_FORMAT;
      strcpy(outpam.tuple_type, cmdline.tupletype);
  
      pm_message("Writing %d channel PAM image", outpam.depth);
  
      pnm_writepaminit(&outpam);
  
      outputRaster(inpam, cmdline.nInput, outpam);
  
      exit(0);
  }
  
  
  
  
  
  
  
  
  
  
  