       /***********************************************
       *
       *       file d:\cips\scale.c
       *
       *       Functions: This file contains
       *          zoom_image_array
       *          shrink_image_array
       *          interpolate_pixel
       *          average_pixel
       *          median_pixel
       *          get_scaling_options
       *          blank_image_array
       *
       *       Purpose:
       *          These functions implement image array
       *          zooming (enlarging) and shrinking.
       *
       *       External Calls:
       *          wtiff.c - does_not_exist
       *                    round_off_image_size
       *                    create_allocate_tiff_file
       *                    write_array_into_tiff_image
       *          tiff.c - read_tiff_header
       *          rtiff.c - read_tiff_image
       *          rstring.c - read_string
       *          numcvrt.c - get_integer
       *          filter.c - median_of
       *
       *       Modifications:
       *          8 April 1992 - created
       *
       *************************************************/

#include "d:\cips\cips.h"
#include <malloc.h>

     /*******************************************
     *
     *   zoom_image_array(...
     *
     *   This function zooms in on an input
     *   image array.  It zooms by enlarging
     *   an input image array and writing the
     *   resulting image arrays to an output
     *   image file.  It can zoom or enlarge by
     *   a factor of 2 or 4.
     *
     *   You can zoom or enlarge an image array
     *   by using either the replication or
     *   interpolation methods.
     *
     *******************************************/


zoom_image_array(in_name, out_name, the_image, out_image,
          il, ie, ll, le, scale, method)
   char   in_name[], out_name[], method[];
   int    il, ie, ll, le, scale;
   short  the_image[ROWS][COLS],
          out_image[ROWS][COLS];
{
   int    A, B, a, b, count, factor, i, j, length, width;
   struct tiff_header_struct image_header;

           /*******************************************
           *
           *   Check the scale factor.  If it is not
           *   a valid factor (2 or 4), then set
           *   it to 2.
           *
           *******************************************/

   factor = scale;
   if(factor != 2 &&
      factor != 4) factor = 2;

   if(does_not_exist(out_name)){
      printf("\n\n output file does not exist %s", out_name);
      read_tiff_header(in_name, &image_header);
      image_header.image_length = ROWS*factor;
      image_header.image_width  = COLS*factor;
      create_allocate_tiff_file(out_name, &image_header,
                                out_image);
   }  /* ends if does_not_exist */

           /*******************************************
           *
           *   Let me try to explain the nested loops
           *   shown below.
           *
           *   We will enlarge the_image by the factor.
           *   Therefore, we want to divide the_image
           *   into parts of size ROWS/factor by
           *   COLS/factor.  We will loop through
           *   the_image parts ROWS/factor and COLS/factor
           *   using the loops over i and j.
           *
           *   We divided the_image into parts so we must
           *   include all of these parts.  That is why we
           *   do the loops over A and B.  There are
           *   factor*factor parts.
           *
           *   Finally, we do the loops over a and b.
           *   We must replicate every element in the_image
           *   factor*factor times and put these into
           *   out_image.  The a and b loops perform this
           *   task.
           *
           *   The equations inside the []'s for
           *   the_image and out_image are also confusing.
           *   If you work them out, you'll see that we
           *   are bouncing through the image arrays
           *   and fitting the pixels into the right
           *   places.
           *
           *   The final proof is that this works.
           *
           *   One final note:  the factor should divide
           *   evenly into ROWS.  For example, ROWS=100
           *   so using a factor of 8 is not good.
           *   100/8 = 12.5 and this leave you with
           *   an empty strip along the right and
           *   bottom edges of the out_image.
           *
           *******************************************/

           /*******************************************
           *
           *   Replication method
           *
           *******************************************/

   if(method[0] == 'r' || method[0] == 'R'){
      read_tiff_image(in_name, the_image, il, ie, ll, le);
      count = 1;
      for(A=0; A<factor; A++){
       for(B=0; B<factor; B++){
        for(i=0; i<ROWS/factor; i++){
         for(j=0; j<COLS/factor; j++){
          for(a=0; a<factor; a++){
           for(b=0; b<factor; b++){
             out_image[factor*i+a][factor*j+b] =                  
              the_image[i+A*ROWS/factor][j+B*COLS/factor];
           }  /* ends loop over b */
          }  /* ends loop over a */
         }  /* ends loop over j */
        }  /* ends loop over i */
        printf("\nzooming replication %3d of %3d",
               count++, factor*factor);
        write_array_into_tiff_image(out_name, out_image,
            1+A*ROWS, 1+B*COLS, 101+A*ROWS, 101+B*COLS);
       }  /* ends loop over B */
      }  /* ends loop over A */
   }  /* ends replication method */

           /***************************
           *
           *   Interpolation method
           *
           ****************************/

   if(method[0] == 'i' || method[0] == 'I'){
      read_tiff_image(in_name, the_image, 
                      il, ie, ll, le);
      count = 1;
      for(A=0; A<factor; A++){
         for(B=0; B<factor; B++){
          for(i=0; i<ROWS/factor; i++){
           for(j=0; j<COLS/factor; j++){
            for(a=0; a<factor; a++){
             for(b=0; b<factor; b++){
                out_image[factor*i+a][factor*j+b] =
                  interpolate_pixel(the_image, A, B,
                              i, j, a, b, factor);
             }  /* ends loop over b */
            }  /* ends loop over a */
           }  /* ends loop over j */
          }  /* ends loop over i */
       printf("\nzooming interpolation %3d of %3d",
                     count++, factor*factor);
       write_array_into_tiff_image(out_name, out_image,
                 1+A*ROWS, 1+B*COLS, 
                 101+A*ROWS, 101+B*COLS);
     }  /* ends loop over B */
    }  /* ends loop over A */
   }  /* ends interpolation method */


}  /* ends zoom_image_array */




    /***********************************************
    *
    *    interpolate_pixel(...
    *
    *    This function interpolates between pixel
    *    values and returns the interlopated value.
    *
    ***********************************************/

interpolate_pixel(the_image, A, B, i, j, a, b, factor)
   int   A, B, a, b, factor, i, j;
   short the_image[ROWS][COLS];
{
   int   num, x = 0, y = 0;
   short diff, result;

   if(a > 0) y = 1;
   if(b > 0) x = 1;
   diff = the_image[y+i+A*ROWS/factor][x+j+B*COLS/factor] -
          the_image[i+A*ROWS/factor][j+B*COLS/factor];

          /***********************************************
          *
          *    If you are at the edge of the input image
          *    array, then you cannot interpolate to the
          *    next point because there is no next point.
          *    Therefore, set the diff to 0.
          *
          ***********************************************/

   if((y+i+A*ROWS/factor) >= ROWS) diff = 0;
   if((x+j+B*COLS/factor) >= COLS) diff = 0;

   num = a+b;
   if(num > factor) num = factor;
   result = the_image[i+A*ROWS/factor][j+B*COLS/factor] +
            num*diff/factor;
   return(result);
}  /* ends interpolate_pixel */



     /*******************************************
     *
     *   shrink_image_array(...
     *
     *   This function shrinks a part of an
     *   image.  It takes a part of an input
     *   image (described by il1, ie1, ll1, le1)
     *   shrinks a 200x200 or 400x400 area down
     *   to a 100x100 array, and writes this result
     *   to an output file.  The location in the
     *   output file is described by il2, ie2,
     *   ll2, le2.
     *
     *   You can shrink the input image area
     *   by using either the averaging, median,
     *   or corner method.
     *
     *******************************************/

shrink_image_array(in_name, out_name, the_image, out_image,
          il1, ie1, ll1, le1, il2, ie2, ll2, le2,
          scale, method)
   char   in_name[], out_name[], method[];
   int    il1, ie1, ll1, le1,
          il2, ie2, ll2, le2, scale;
   short  the_image[ROWS][COLS],
          out_image[ROWS][COLS];
{
   int    A, B, a, b, count, factor, i, j, length, width;
   struct tiff_header_struct image_header;

           /*******************************************
           *
           *   Check the scale factor.  If it is not
           *   a valid factor (2 or 4), then set
           *   it to 2.
           *
           *******************************************/

   factor = scale;
   if(factor != 2 &&
      factor != 4) factor = 2;

   if(does_not_exist(out_name)){
      printf("\n\n output file does not exist %s", out_name);
      read_tiff_header(in_name, &image_header);
      image_header.image_length = ROWS;
      image_header.image_width  = COLS;
      create_allocate_tiff_file(out_name, &image_header,
                                out_image);
   }  /* ends if does_not_exist */

   read_tiff_header(in_name, &image_header);

           /*******************************************
           *
           *   Let me try to explain the nested loops
           *   shown below.
           *
           *   We will shrink the_image by the factor.
           *   Therefore, we want to read in factor*factor
           *   image arrays and produce one ROWS by COLS
           *   array for writing to disk.
           *   That is why we loop over A and B.
           *
           *   We want to set every pixel in the out_image
           *   array so we loop over i and j.
           *
           *   The equations inside the out_image []'s
           *   look a little strange.  What we are doing is
           *   setting every element and moving over every
           *   time through the loops over A and B.  The first 
           *   loop is for i=0,49 then i=50,99 for a factor=2
           *   and ROWS=100.
           *
           *   The final proof is that this works.
           *
           *   One final note:  the factor should divide
           *   evenly into ROWS.  For example, ROWS=100
           *   so using a factor of 8 is not good.
           *   100/8 = 12.5 and this leave you with
           *   an empty strip along the right and
           *   bottom edges of the out_image.
           *
           *******************************************/

           /********************************
           *
           *   Corner method
           *
           *********************************/

   if(method[0] == 'c' || method[0] == 'C'){
      count = 1;
      for(A=0; A<factor; A++){
       for(B=0; B<factor; B++){
        printf("\n shrinking by corner %3d of %3d",
                     count++, factor*factor);
        if(image_header.image_length < il1+A*ROWS   ||
           image_header.image_width  < ie1+B*COLS)
           blank_image_array(the_image);
        else
           read_tiff_image(in_name, the_image,
                           il1+A*ROWS, ie1+B*COLS,
                           ll1+A*ROWS, le1+B*COLS);
        for(i=0; i<ROWS/factor; i++){
         for(j=0; j<COLS/factor; j++){
            out_image[i+A*ROWS/factor][j+B*COLS/factor] =
                     the_image[factor*i][factor*j];
         }  /* ends loop over j */
        }  /* ends loop over i */
       }  /* ends loop over B */
      }  /* ends loop over A */
      write_array_into_tiff_image(out_name, out_image,
                                  il2, ie2, ll2, le2);
   } /* ends corner method */

           /******************************
           *
           *   Average Method
           *
           ******************************/

   if(method[0] == 'a' || method[0] == 'A'){
      count = 1;
      for(A=0; A<factor; A++){
       for(B=0; B<factor; B++){
        printf("\n shrinking by average %3d of %3d",
                     count++, factor*factor);
        if(image_header.image_length < il1+A*ROWS   ||
           image_header.image_width  < ie1+B*COLS)
           blank_image_array(the_image);
        else
           read_tiff_image(in_name, the_image,
                          il1+A*ROWS, ie1+B*COLS,
                          ll1+A*ROWS, le1+B*COLS);
        for(i=0; i<ROWS/factor; i++){
         for(j=0; j<COLS/factor; j++){
             out_image[i+A*ROWS/factor][j+B*COLS/factor] =
                   average_pixel(the_image, factor, i, j);
         }  /* ends loop over j */
        }  /* ends loop over i */
       }  /* ends loop over B */
      }  /* ends loop over A */
      write_array_into_tiff_image(out_name, out_image,
                                  il2, ie2, ll2, le2);
   } /* ends average method */

           /************************
           *
           *   Median Method
           *
           *************************/

   if(method[0] == 'm' || method[0] == 'M'){
      count = 1;
      for(A=0; A<factor; A++){
       for(B=0; B<factor; B++){
        printf("\n shrinking by median %3d of %3d",
                     count++, factor*factor);
        if(image_header.image_length < il1+A*ROWS   ||
           image_header.image_width  < ie1+B*COLS)
           blank_image_array(the_image);
        else
           read_tiff_image(in_name, the_image,
                           il1+A*ROWS, ie1+B*COLS,
                           ll1+A*ROWS, le1+B*COLS);
        for(i=0; i<ROWS/factor; i++){
         for(j=0; j<COLS/factor; j++){
            out_image[i+A*ROWS/factor][j+B*COLS/factor] =
                    median_pixel(the_image, factor, i, j);
         }  /* ends loop over j */
        }  /* ends loop over i */
       }  /* ends loop over B */
      }  /* ends loop over A */
      write_array_into_tiff_image(out_name, out_image,
                                  il2, ie2, ll2, le2);
   } /* ends median method */
}  /* ends shrink_image_array */



    /***********************************************
    *
    *   average_pixel(...
    *
    *   This function calculates the average
    *   pixel value of a factor x factor array
    *   of pixels inside the the_image array.
    *   The coordinates i and j point to the upper 
    *   left hand corner of the small array.
    *
    ***********************************************/

average_pixel(the_image, factor, i, j)
   int   factor, i, j;
   short the_image[ROWS][COLS];
{
   int a, b, result = 0;

   for(a=0; a<factor; a++)
      for(b=0; b<factor; b++)
         result = result + the_image[factor*i+a][factor*j+a];
   result = result/(factor*factor);

   return(result);
}  /* ends average_pixel */



    /***********************************************
    *
    *   median_pixel(...
    *
    *   This function calculates the median
    *   pixel value of a factor x factor array
    *   of pixels inside the the_image array.
    *   The coordinates i and j point to the upper 
    *   left hand corner of the small array.
    *
    ***********************************************/

median_pixel(the_image, factor, i, j)
   int   factor, i, j;
   short the_image[ROWS][COLS];
{
   int   a, b, count, ff, result = 0;
   short *elements;

   ff       = factor*factor;
   elements = (short *) malloc(ff * sizeof(short));

     count = 0;
   for(a=0; a<factor; a++){
         for(b=0; b<factor; b++){
            elements[count] = the_image[factor*i+a][factor*j+b];
              count++;
        }
     }

   result = median_of(elements, &ff);
   free(elements);
   return(result);

}  /* ends median_pixel */



    /***********************************************
    *
    *   blank_image_array(...
    *
    *   This function blanks out an image array
    *   by filling it with zeros.
    *
    ***********************************************/

blank_image_array(image)
   short image[ROWS][COLS];
{
   int i, j;
   for(i=0; i<ROWS; i++)
      for(j=0; j<COLS; j++)
         image[i][j] = 0;
}  /* ends blank_image_array */



    /***********************************************
    *
    *    get_scaling_options(...
    *
    *    This function queries the user for the
    *    parameters needed to perform scaling.
    *
    ***********************************************/


get_scaling_options(zoom_shrink, scale, method)
   int *scale;
   char method[], zoom_shrink[];
{
   int not_finished = 1, response;

   while(not_finished){
      printf("\n\t1. Zoom or Shrink is - %s", zoom_shrink);
      printf("\n\t2. Scale factor is %d", *scale);
      printf("\n\t3. Scaling Method is - %s", method);
      printf("\n\t     Replication or Interpolation for Zooming"
             "\n\t     Averaging Median or Corner for Shrinking");
      printf("\n\n\tEnter choice (0 = no change) _\b");
      get_integer(&response);

      if(response == 0){
        not_finished = 0;
      }

      if(response == 1){
         printf("\nEnter Zoom or Shrink (z or s) __\b");
         read_string(zoom_shrink);
      }

      if(response == 2){
         printf("\nEnter Scale Factor (2 or 4) __\b");
         get_integer(scale);
      }

      if(response == 3){
         printf("\nEnter Scaling Method: "
                "Replication or Interpolation for Zooming"
                "\n                      "
                "Averaging Median or Corner for Shrinking"
                "\n\t__\b");
         read_string(method);
      }

   }  /* ends while not_finished */
}  /* ends get_scaling_options */
