 /*
  * Khoros: $Id: lvpostscr.c,v 1.4 1991/12/18 09:25:49 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lvpostscr.c,v 1.4 1991/12/18 09:25:49 dkhoros Exp $";
#endif

 /*
  * $Log: lvpostscr.c,v $
 * Revision 1.4  1991/12/18  09:25:49  dkhoros
 * HellPatch3
 *
  */

/*
 *----------------------------------------------------------------------
 *
 * 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 to 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: lvpostscr.c
 >>>>
 >>>>      Program Name: vpostscr
 >>>>
 >>>> Date Last Updated: Fri Dec  6 23:30:27 1991 
 >>>>
 >>>>          Routines: lvpostscr - the library call for vpostscr
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


/* -library_includes */
float maxpagewidth; /* Width of output page in inches */
float maxpageheight; /* Height of output page in inches */
/* -library_includes_end */


/****************************************************************
*
* Routine Name: lvpostscr - library call for vpostscr
*
* Purpose:
*    
*    Format  a  Khoros  image  in  Postscript,  suitable  for   a
*    LaserWriter
*    
*    

* Input:
*    
*    file           file descriptor to write the output to
*    
*    image          pointer to xvimage structure to be processed
*    
*    force          flag to force output of the current page
*    
*    photo_neg      flag to  indicate  that  photonegative  output  is
*                   desired
*    
*    wflg           flag to indicate that the given  width  is  to  be
*                   used rather than the computed one
*    
*    hflg           flag to indicate that the given height  is  to  be
*                   used rather than the computed one
*    
*    xflg           flag to indicate that the given X position  is  to
*                   be used rather than the computed one
*    
*    yflg           flag to indicate that the given Y position  is  to
*                   be used rather than the computed one
*    
*    def_width      tells what the desired output width is (inches)
*    
*    def_height     tells what the desired output height is (inches)
*    
*    def_xoffset    tells what the desired X offset is (inches)
*    
*    def_yoffset    tells what the desired Y offset is (inches)
*    
*    landscape      indicates if output should be in landscape mode
*    
*    

* Output:
*    
*    file           this descriptor receives the Postscript output
*    
*    Return Value:  1 on success, 0 on failure.
*    
*    

*
* Written By: Scott Wilson, Mark Young
*    
*    Fixed lvpostscr so that large bit images can be printed  out
*    Oct,  1991  added  fflush statement to flush the rest of the
*    stdout buffer. Dec 6, 1991
*    
*    

****************************************************************/


/* -library_def */
int
lvpostscr(file, image, force, photo_neg, wflg, hflg, xflg, yflg,
            def_width, def_height, def_xoffset, def_yoffset, landscape)
FILE    *file;
struct  xvimage  *image;
int     force, photo_neg, wflg, hflg, xflg, yflg, landscape;
float   def_width, def_height, def_xoffset, def_yoffset;
/* -library_def_end */

/* -library_code */
{
      char      *ctime();
      time_t     time(), clock;
      int        rows, cols, sx, sy, dx, dy;
      float      ax, ay;
      unsigned   char *data;
      float      width = def_width, height = def_height, 
                 xoffset = def_xoffset, yoffset = def_yoffset;
      
      /*
       * Intiailize values for the "set_default_values" routine.  This routine
       * is used to make some assumtions about the aspect ratio and also the
       * position of the output image on the page.
       */

      ax   = image->pixsizx;
      ay   = image->pixsizy;

      if (landscape)
      {
         maxpagewidth = 11.0;
         maxpageheight = 8.5;
      }
      else
      {
         maxpagewidth = 8.5;
         maxpageheight = 11.0;
      }

      rows = (int) image->col_size;
      cols = (int) image->row_size;
      set_default_values(&width, &height, &xoffset, &yoffset, ax, ay, rows, 
                         cols, wflg, hflg, xflg, yflg);

      /*
       * error check to make sure that we have the right type of image
       * and that the desired output image will on the screen.
       */
      if (image->data_storage_type != VFF_TYP_1_BYTE && 
          image->data_storage_type != VFF_TYP_BIT)
      {
         (void) fprintf(stderr,"\n\nlvpostscr: Operates on BYTE or BIT ");
         (void) fprintf(stderr,"images only!\n\n");
         return(0);
      }

      if (!((image->map_scheme == VFF_MS_NONE ||
           (image->map_scheme == VFF_MS_ONEPERBAND ||
           image->map_scheme == VFF_MS_SHARED) &&
           image->map_storage_type == VFF_MAPTYP_1_BYTE &&
           (image->color_space_model == VFF_CM_ntscRGB ||
            image->color_space_model == VFF_CM_genericRGB))))
        {
          (void)fprintf(stderr,"lvpostscr: Unsupported color image for output!\n");
          (void)fprintf(stderr,"Supported color output types:\n");
          (void)fprintf(stderr,"1. Normal greyscale - VFF_MS_NONE\n");
          (void)fprintf(stderr,"2. 24 bit, 3 plane RGB(ntsc or generic)\n");
          (void)fprintf(stderr,"3. 8 bit, 1 plane, mapped RGB(ntsc or generic)\n");
          (void)fprintf(stderr,"Please convert your image to one of these types!\n");
          return(0);
        }
          
      if (photo_neg && image->num_data_bands != 1)
        {
          (void)fprintf(stderr,"lvpostscr: Cannot invert multi-band image!\n");
          return(0);
        }

      if ((xoffset + width) > maxpagewidth || (yoffset + height) > maxpageheight)
      {
         (void) fprintf(stderr,"\n\nlvpostscr: Requested image layout too ");
         (void) fprintf(stderr,"large for page!\n\n");
         return(0);
      }

      /*
       * The scaling factor and translation distance is in terms of 
       * 72 pixels per inch.  So we multiple the number of inches
       * by 72 and truncate to the nearest pixel value.
       */
      sx = (int) (width * 72.0);
      sy = (int) (height * 72.0);
      dx = (int) (xoffset * 72.0);
      dy = (int) (yoffset * 72.0);
      
      /*
       * Write header information.
       */
      (void) fprintf(file,"%%!PS-Adobe-2.0 EPSF-1.2\n");
      (void) fprintf(file,"%%%%DocumentFonts: Courier\n");
      (void) fprintf(file,"%%%%Title: Khoros Postscript Image Document\n");
      (void) fprintf(file,"%%%%Creator: vpostscr\n");
      (void) time(&clock);
      (void) fprintf(file,"%%%%CreationDate: %s",ctime(&clock));
      (void) fprintf(file,"%%%%BoundingBox: %d %d %d %d\n",dx,dy, dx+sx, dy+sy);
      (void) fprintf(file,"%%%%Pages: 1\n");
      (void) fprintf(file,"%%%%EndComments\n");
      (void) fprintf(file,"initgraphics\n");
      (void) fprintf(file, "save\n");
      (void) fprintf(file,"%%%%EndProlog\n");
      (void) fprintf(file,"%%%%Page: 1 1\n");

      
      /* Print scale and translation information. */
      if (landscape)
      {
         (void) fprintf(file, "90 rotate\n");
         (void) fprintf(file, "0 -%d translate\n", sy);
         (void) fprintf(file, "%d -%d translate\n",dy,dx);
      }
      else
      {
         (void) fprintf(file, "%d %d translate\n",dx,dy);
      }
      (void) fprintf(file, "%d %d scale\n",sx,sy);

      if (image->data_storage_type == VFF_TYP_1_BYTE)
      {
         if (photo_neg)
         {
            if (! lvinvert(image))
            {
               (void) fprintf(stderr,"lvinvert failed!\n");
               return(0);
            }
         }
         print_byte_image(file, image, rows, cols);
      }
      else /* BIT */
      {
         data = (unsigned char *) image->imagedata;
         print_bit_image(file, data, rows, cols, photo_neg);
      }

      (void) fprintf(file, "restore\n");
      if (force)
      {
         (void) fprintf(file, "showpage\n");
      }
        /* flush the file to write the last little bit in the buffer */
      fflush(file);
      return(1);
}


/*****************************************************
                        genrev
*****************************************************/
genrev(p)
unsigned char *p;
{
    /* Generate an array of bit-reverse characters */
    int i;
    unsigned char j,k;

    for (i=0; i<256; i++)
    {
        j = i;
        k = 0;
        k |= (j >> 7) & (1 << 0); /* Bit 7 to Bit 0 */
        k |= (j >> 5) & (1 << 1); /* Bit 6 to Bit 1 */
        k |= (j >> 3) & (1 << 2); /* Bit 5 to Bit 2 */
        k |= (j >> 1) & (1 << 3); /* Bit 4 to Bit 3 */
        k |= (j << 1) & (1 << 4); /* Bit 3 to Bit 4 */
        k |= (j << 3) & (1 << 5); /* Bit 2 to Bit 5 */
        k |= (j << 5) & (1 << 6); /* Bit 1 to Bit 6 */
        k |= (j << 7) & (1 << 7); /* Bit 0 to Bit 7 */
        p[i]=k;
    }
}


/*****************************************************
                   set_default_values
*****************************************************/
set_default_values(width, height, xoffset, yoffset, ax, ay, 
                   rows, cols, wflg, hflg, xflg, yflg)
float   *width, *height, *xoffset, *yoffset;
int     rows, cols, wflg, hflg, xflg, yflg;
float   ax, ay;
{
      /*  Setup default to 4x4, 4x? or ?x4 picture  */
      if (wflg == 0 && hflg == 0)  
      {
         if (rows*ay >= cols*ax)
         {
            *height = 4.0;
            *width = 4.0*(cols*ax)/(rows*ay);
         }
         else
         {
            *width = 4.0;
            *height = 4.0*(rows*ay)/(cols*ax);
         }
      }
      else if (wflg == 0 && hflg != 0) 
         *width = (*height) * (cols * ax)/(rows * ay);

      else if (wflg != 0 && hflg == 0) 
         *height = (*width) * (rows * ay)/(cols * ax);


      if (xflg == 0) 
         *xoffset = (maxpagewidth - *width)/2.0;

      if (yflg == 0) 
         *yoffset = (maxpageheight - *height)/2.0;
}


/*****************************************************
                   print_byte_image
*****************************************************/
print_byte_image(file, image, rows, cols)
struct xvimage *image;
FILE *file;
int   rows, cols;
{
     int        i, j;
     unsigned char *ptr,*p1,*p2,*p3; /* Data access variables */
     unsigned char *mr,*mg,*mb;      /* Map access variables */

     if (image->map_scheme == VFF_MS_NONE && image->num_data_bands == 1)
       {
          /* Have a standard 1 plane 8 bit greyscale image */
          (void) fprintf(file, "/picstr %d string def\n",cols);
          (void) fprintf(file, "%d %d 8 [%d 0 0 -%d 0 %d]\n",cols,rows,cols,rows,rows);
          (void) fprintf(file, "{currentfile picstr readhexstring pop} image\n");
 
          ptr = (unsigned char *)(image->imagedata);
          for (i = 0; i < rows; i++)
          {
              for (j = 0; j < cols; j++)
                 (void) fprintf(file, "%02x", *ptr++);
 
              (void) fprintf(file, "\n");
          }
       }
     else  /* Have a color image to deal with */
       {
         /* Declare three strings, one for RED, GREEEN, and BLUE */
         (void) fprintf(file, "/rstr %d string def\n",cols);
         (void) fprintf(file, "/gstr %d string def\n",cols);
         (void) fprintf(file, "/bstr %d string def\n",cols);

         /* Set up the source and mapping */
         (void) fprintf(file, "%d %d 8 [%d 0 0 -%d 0 %d]\n",cols,rows,cols,rows,rows);

         /* Set up the read procedures */
         (void)fprintf(file,"{currentfile rstr readhexstring pop}\n");
         (void)fprintf(file,"{currentfile gstr readhexstring pop}\n");
         (void)fprintf(file,"{currentfile bstr readhexstring pop}\n");

         /* Set up the colorimage operator with multiple procedures and 3 colors */
         (void)fprintf(file,"true 3 colorimage\n");

         /* Start burping out the data */
         if (image->map_scheme == VFF_MS_NONE && image->num_data_bands == 3)
           {
             /* Have a 24 bit, 3 plane RGB image */
             p1 = (unsigned char *)(image->imagedata);
             p2 = p1 + rows*cols;
             p3 = p2 + rows*cols;
             for (i=0; i< rows; i++)
               {
                 for (j=0; j<cols; j++) /* RED */
                   (void)fprintf(file,"%02x",*p1++);
                 fprintf(file,"\n");
                 for (j=0; j<cols; j++) /* GREEN */
                   (void)fprintf(file,"%02x",*p2++);
                 fprintf(file,"\n");
                 for (j=0; j<cols; j++) /* BLUE */
                   (void)fprintf(file,"%02x",*p3++);
                 fprintf(file,"\n");
               }
           }
         else if ((image->map_scheme == VFF_MS_ONEPERBAND || 
                  image->map_scheme == VFF_MS_SHARED) &&
                  image->num_data_bands == 1)
           {
             /* Have a 1 plane, 8-bit image that has a 3-band map, of type RGB */
             ptr = (unsigned char *)(image->imagedata);
             mr = (unsigned char *)(image->maps);
             mg = mr + image->map_col_size;
             mb = mg + image->map_col_size;
             for (i=0; i<rows; i++)
               {
                 p1 = ptr;
                 for (j=0; j<cols; j++) /* RED */
                   (void)fprintf(file,"%02x",mr[*p1++]);
                 (void)fprintf(file,"\n");
                 p1 = ptr;
                 for (j=0; j<cols; j++) /* GREEN */
                   (void)fprintf(file,"%02x",mg[*p1++]);
                 (void)fprintf(file,"\n");
                 p1 = ptr;
                 for (j=0; j<cols; j++) /* BLUE */
                   (void)fprintf(file,"%02x",mb[*p1++]);
                 (void)fprintf(file,"\n");
                 ptr += cols;
               }
           } 
       }
}

/*****************************************************
                   print_bit_image
*****************************************************/
print_bit_image(file, data, rows, cols, photo_neg)
FILE     *file;
unsigned char *data;
int      rows, cols, photo_neg;
{
     int        k, i, j;
     unsigned   char *ptr, rev[256];

     k = (cols+7)/8;

     /* Flip the bits around to match the POSTSCRIPT idea of pixels */
     ptr = (unsigned char *) data;
     genrev(rev);
     for (i = 0; i < k*rows; i++)
     {
         *ptr = rev[*ptr]; ptr++;
     }

     /* Do photonegative if requested */
     if (photo_neg)
     {
        ptr = (unsigned char *) data;
        for (i = 0; i < k*rows; i++)
        {
            *ptr = ~(*ptr); ptr++;
        }
     }

     (void) fprintf(file, "/picstr %d string def\n",k);
     (void) fprintf(file, "%d %d 1 [%d 0 0 -%d 0 %d]\n",cols,rows,cols,
                    rows,rows);
     (void) fprintf(file, "{currentfile picstr readhexstring pop} image\n");

     /* Spit it out */
     ptr = (unsigned char *) data;
     for (i = 0; i < rows; i++)
     {
         for (j = 0; j < k; j++)
             (void) fprintf(file, "%02x", *ptr++);

         (void) fprintf(file, "\n");
     }
}
/* -library_code_end */
