 /*
  * Khoros: $Id: lvbandcomb.c,v 1.2 1992/03/25 17:30:26 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lvbandcomb.c,v 1.2 1992/03/25 17:30:26 dkhoros Exp $";
#endif

 /*
  * $Log: lvbandcomb.c,v $
 * Revision 1.2  1992/03/25  17:30:26  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"        /* Copyright 1991 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: lvbandcomb.c
 >>>>
 >>>>      Program Name: vbandcomb
 >>>>
 >>>> Date Last Updated: Tue Mar  5 22:22:46 1991 
 >>>>
 >>>>          Routines: lvbandcomb - the library call for vbandcomb
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


/* -library_includes */
#include "vipl/lvbandcomb.h"

#define IGNOREMAP 0
#define MAPDATA   1
#define XFERMAP   2
/* -library_includes_end */


/****************************************************************
*
* Routine Name: lvbandcomb - library call for vbandcomb
*
* Purpose:
*    
*    Combine all bands from m images into one multiband image
*    
*    
* Input:
*    
*    images         An array of input images.
*    
*    image_num      The number of input images.
*    
*    mapping_type   Integer representing type of mapping to occur.
*    
*    cs_model       Integer representing the color space model of  the
*                   output image.
*    
*    
* Output:
*    
*    newimage       The resulting band combined image.
*    
*    
*
* Written By: Tom Sauer, Mark Young
*    
*    Jan 21  1991  - added map transfer and map data options
*                    to the routine. (Tom & Charlie)
*    
*    
****************************************************************/


/* -library_def */
int
lvbandcomb(newimage, images, image_num, mapping_type, cs_model)

struct xvimage **newimage, *images[];
int image_num, mapping_type, cs_model;
/* -library_def_end */

/* -library_code */
{
   int  i, total_bytes = 0 ;
   int     dsize,dcount,msize,mcount,lsize,lcount;
   unsigned char *newdata, *newmaps;
   unsigned long *sizes;  /* contains the imagedata byte count for all images */
   unsigned long position = 0, numbands = 0;
   char *program = "lvbandcomb";
   struct xvimage *tmpimage;
   int *map_null_list, storage_size;
   int max_map_rowsize = 0, max_map_colsize = 0, map_num = -1;
   int new_map_size;


   newmaps = NULL; 
   map_null_list = (int *) malloc(sizeof(int) * image_num);
   bzero(map_null_list, sizeof(int) * image_num);

   /* if no image to process, we must exit */
   if (image_num == 0) {
      (void) fprintf(stderr,
              "%s: ERROR No images avaliable to combine\n", program);
      return(0);
   }

   
       /* make sure the first input only contains one image */

    if ( ! (proper_num_images(program,images[0],1,FALSE))) {
        (void) fprintf(stderr,
               "%s: ERROR All inputs must contain only one image\n"
               , program);
        return(0);
    }

      /* if the mapping type is MAPDATA then make sure the first image is of */
      /* storage type BYTE, If it is not bomb out.                 */

   if (mapping_type == MAPDATA) {
     if ( ! (propertype(program, images[0], VFF_TYP_1_BYTE, FALSE))) {
        (void) fprintf(stderr,
             "%s: ERROR Image must have a storage type of BYTE \n", program);
        (void) fprintf(stderr,"when the map flag is specified\n");
        return(0);
     }
   }

       /* loop through all the images and make sure they all have the */
       /* same type, number of images, and size                       */

   for ( i = 0 ; i < image_num ; i++ ) {
      if ( ! (matchtype(program,images[0],images[i],FALSE))) {
          (void) fprintf(stderr,
                  "%s: ERROR All Images must have the same storage type\n"
                  , program);
          return(0);
       }

      if ( ! (match_num_images(program,images[0],images[i],FALSE))) {
          (void) fprintf(stderr,
                  "%s: ERROR All inputs must only have one image\n"
                  , program);
          return(0);
        }
       
      if ( ! (matchsize(program,images[0],images[i],FALSE))) {
          (void) fprintf(stderr,
                  "%s: ERROR All images must be the same size\n"
                  , program);
          return(0);
        }
     }
       
      /* if map flag is set then check to make sure the data can be mapped, */
      /* if it can then map it. We must be careful here, the returned image */
      /* will take on the data type of the map */
 
   if (mapping_type == MAPDATA)     /* (-m 1) need to map the data */
   {
      for ( i = 0 ; i < image_num ; i++) {
         if ( images[i]->map_scheme != VFF_MS_NONE) {
            if ( ! (lvmapdata(images[i]))) {
               (void) fprintf(stderr,
                       "%s: ERROR lvmapdata failed\n", program);
               return(0);
            }
         }
      }

      for ( i = 0 ; i < image_num ; i++ ) {
         if ( ! (matchtype(program,images[0],images[i],FALSE))) {
             (void) fprintf(stderr,
                "%s: ERROR After Mapping the data, all Images do not have\n"
                     , program);
             (void) fprintf(stderr," the same storage type\n");
             return(0);
          }
       }
   }
        /* the mapping_type is XFERMAP, error check so that we can
         * see if the maps can be transfered
         */
   else if (mapping_type == XFERMAP)   /* (-m 2) xfer map data */
   {
      map_num = -1;
      max_map_rowsize = 0;
      max_map_colsize = 0;
      for ( i = 0 ; i < image_num ; i++ ) 
      {
         if ( (proper_map_type(program,images[i],VFF_MAPTYP_NONE,FALSE)))
         {
                map_null_list[i] = 1;
         }
         else
         {
           map_num = i;                  /* get max size of maps */
           if (max_map_rowsize < images[i]->map_row_size)
                  max_map_rowsize = images[i]->map_row_size;
           if (max_map_colsize < images[i]->map_col_size)
                  max_map_colsize = images[i]->map_col_size;
         }
      }  
      if( map_num != -1)
      {
         for ( i = 0 ; i < image_num ; i++ ) 
         {
            if ( map_null_list[i] != 1)
            {
               if (!(match_map_type(program,images[map_num],images[i],FALSE))) 
               {
                   (void) fprintf(stderr,
                      "%s: ERROR All input images must have the same map type \
to transfer maps to the new multiband image,\n",program);
                   (void) fprintf(stderr," and the same storage type\n");
                   return(0);
               }
            }
          }
       }
   }

      /* point to the first image, a temporary pointer */

   tmpimage = (struct xvimage *) images[0];

       /* malloc room for the sizes array, which will contain the byte */
       /* count for each image */

   sizes   = (unsigned long *) malloc(sizeof(unsigned long) * image_num);
   if (sizes == NULL) {
      (void) fprintf(stderr, 
             "%s: ERROR insufficient  memory avaliable\n", program);
      return(0);
   }

    /* find the size (in bytes) of the imagedata for all images */

  for ( i = 0 ; i < image_num ; i++)  
  {
     if (! (imagesize(images[i],&dsize,&dcount,&msize,&mcount,&lsize,&lcount)))
     {
            (void) fprintf(stderr,
                    "%s: ERROR imagesize failed\n", program);
            return(0);
     }
     sizes[i] = dsize;
     total_bytes += dsize;
  }

     /* malloc room for the new image that will contain all bands for the */
     /* input images */

  newdata = (unsigned char *) malloc(total_bytes);
  if ( newdata == NULL ) {
     (void) fprintf(stderr, 
            "%s: ERROR insufficient  memory avaliable\n", program);
     return(0);
  }
      /* concatenate all data bands */

  for ( i = 0 ; i < image_num; i++ ) {
      bcopy(images[i]->imagedata, &newdata[position], sizes[i]);
      position += sizes[i];
      numbands += images[i]->num_data_bands;
  }

  if (mapping_type == XFERMAP)
  {
      if(map_num != -1)
      {
         switch(images[map_num]->map_storage_type)
         {
             case VFF_MAPTYP_1_BYTE:
                  tmpimage->map_storage_type = VFF_MAPTYP_1_BYTE;
                  storage_size = sizeof(char);
                  break;
             case VFF_MAPTYP_2_BYTE:
                  tmpimage->map_storage_type = VFF_MAPTYP_2_BYTE;
                  storage_size = sizeof(short);
                  break;
             case VFF_MAPTYP_4_BYTE:
                  tmpimage->map_storage_type = VFF_MAPTYP_4_BYTE;
                  storage_size = sizeof(int);
                  break;
             case VFF_MAPTYP_FLOAT:
                  tmpimage->map_storage_type = VFF_MAPTYP_FLOAT;
                  storage_size = sizeof(float);
                  break;
             case VFF_MAPTYP_DOUBLE:
                  tmpimage->map_storage_type = VFF_MAPTYP_DOUBLE;
                  storage_size = sizeof(double);
                  break;
             case VFF_MAPTYP_COMPLEX:
                  tmpimage->map_storage_type = VFF_MAPTYP_COMPLEX;
                  storage_size = sizeof(float)*2;
                  break;
         }
         
         new_map_size = storage_size * max_map_rowsize * 
                        max_map_colsize * numbands;
         newmaps = (unsigned char *) malloc(new_map_size);
         if ( newmaps == NULL ) 
         {
            (void) fprintf(stderr, 
                   "%s: ERROR insufficient  memory avaliable for maps\n", 
                    program);
            return(0);
         }
         build_new_maps(newmaps, images, image_num, map_null_list,
                        storage_size, max_map_rowsize, max_map_colsize);
      }
  }



    /* transfer new map data and info to new image */

  tmpimage->imagedata = (char * ) newdata;
  tmpimage->num_data_bands = numbands;
  tmpimage->map_scheme = VFF_MS_NONE;
  if (map_num != -1) 
     tmpimage->map_scheme = VFF_MS_ONEPERBAND;
  tmpimage->map_row_size = max_map_rowsize;
  tmpimage->map_col_size = max_map_colsize;
  tmpimage->map_subrow_size = 0;
  tmpimage->map_enable = VFF_MAP_OPTIONAL;

  if (map_num == -1) 
     tmpimage->map_storage_type = VFF_MAPTYP_NONE;

  tmpimage->maps = (char *) newmaps;
  tmpimage->num_of_images = 1;
     /* if more the 3 bands exist then set the color space model   */
     /* to NONE, This overrides what was passed in.                */
  if ((tmpimage->num_data_bands % 3) != 0) cs_model = 0;
  SET_COLOR_SPACE_MODEL(tmpimage, cs_model);

  *newimage = tmpimage;

  return(1);
  
}  /*** End of main lvbandcomb ***/


/******************************************************************
*
* MODULE NAME:  build_new_maps
*
*     PURPOSE:  Builds new maps for those bands that don't have a
*               map, or have shared maps.
*
*       INPUT:  struct xvimage *images[] - array of input images
*               char *newmaps - pointer to new map data
*               int image_num - number of input images
*               int *map_null_list - pointer to images with no maps.
*               int max_map_rowsize - maximum row size of maps.
*               int max_map_colsize - maximum col size of maps.
*               int map_storage_size - data storage size for map.
*
* CALLED FROM:  lvbandcomb
*
* ROUTINES CALLED:
*
*******************************************************************/

build_new_maps(newmaps, images, image_num, map_null_list,
               map_storage_size, max_map_rowsize, max_map_colsize)

unsigned char *newmaps;
struct xvimage *images[];
int image_num, *map_null_list;
int max_map_rowsize, max_map_colsize, map_storage_size;
{
  int  i, j, k, p, band_num = 0;
  unsigned char *mptr,       /* temporary pointer to map data */
                *optr;       /* pointer to input image map data */
  unsigned long  map_size;
  
  map_size = max_map_rowsize * max_map_colsize * map_storage_size;

                                /* Loop thru each image */
  for (i=0; i < image_num; i++)
  {
                    /* set pointer to start of input map data */
    optr = (unsigned char *) images[i]->maps;
                                /* Loop thru each data band */
    for (j=0; j < images[i]->num_data_bands; j++)
    {
            /*<<<<<<<<<<<<<<  map type NONE  >>>>>>>>>>>>>>>>*/
     if (map_null_list[i] == 1)
      {
        mptr = &newmaps[band_num * map_size];  /* point to new map data */
        for (k=0; k < max_map_rowsize; k++)
        {
          for (p=0; p < max_map_colsize; p++)
          {
            *mptr = p;             /* Generate linear map */
            mptr++;
          }
        }
      }
            /*<<<<<<<<<<<<<<   map type SHARED   >>>>>>>>>>>>>>>>*/
     else if (images[i]->map_scheme == VFF_MS_SHARED)
      {
            /* Check to ensure that all maps are of same size */
            /*  if not, then expand to max size */
                             /* reset pointer to start of input map data */
       optr = (unsigned char *) images[i]->maps;
       if ((images[i]->map_row_size < max_map_rowsize) || (images[i]->map_col_size < max_map_colsize))
       {
         mptr = &newmaps[band_num * map_size];  /* point to new map data */
         for (k=0; k < max_map_rowsize; k++)
         {
          for (p=0; p < max_map_colsize; p++)
          {
            if ((p > images[i]->map_col_size) || (k > images[i]->map_row_size))
               mptr++;         /* skip over unused map data */
            else
            {
               *mptr = *optr;  /* fill in new map with old map data */
               optr++;         /* increment pointers to both maps */
               mptr++;
            }
          }
         }
       }
      else      /* if same size map, just copy old data to new data */
       {
         bcopy(optr, &newmaps[band_num * map_size], map_size);
       }
     }
    else    /*<<<<<<<<<<<  map type ONEPERBAND  >>>>>>>>>>>>>*/
     {
           /* Check to ensure that all maps are of same size */
           /*  if not, then expand to max size */
      if ((images[i]->map_row_size < max_map_rowsize) || (images[i]->map_col_size < max_map_colsize))
      {
        mptr = &newmaps[band_num * map_size];  /* point to new map data */
        for (k=0; k < max_map_rowsize; k++)
        {
         for (p=0; p < max_map_colsize; p++)
         {
           if ((p > images[i]->map_col_size) || (k > images[i]->map_row_size))
              mptr++;         /* skip over unused map data */
           else
           {
              *mptr = *optr;  /* fill in new map with old map data */
              optr++;         /* increment pointers to both maps */
              mptr++;
           }
         }
        }
      }
     else      /* if same size map, just copy old data to new data */
      {
        bcopy(optr, &newmaps[band_num * map_size], map_size);
        optr += map_size;     /* set pointer to next map in image */
      }
    }   /*  end of ONEPERBAND  */

    band_num++;
   }  /* end of data band loop */
  }   /* end of image loop */

}
/* -library_code_end */
