#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <pwd.h>
#include "eps.h"

#ifdef __STDC__
#include <stdlib.h>
#include <string.h>
#endif

#ifdef SOLARIS
#include <sys/systeminfo.h>
#endif


/* 
**  EPS.C -- EPS hardcopy routines.  This code takes an input structure
**  containing the pixels, colormap, and output specifications and creates
**  and Encapsulated PostScript file.
**
**     #include "eps.h"			# flags, macro defs, etc.
**
**	     psim = eps_init ()
**                 eps_print (psim, fp, &data, xdim, ydim, depth, pad)
**	           eps_close (psim)
**
**               eps_setPage (psim, orient, paper_size, scale, flags)
**	         eps_setCmap (psim, &r, &g, &b, ncolors)
**           eps_setCompress (psim, ctype)
**          eps_setColorType (psim, otype)
**	        eps_setLabel (psim, &label)
**	    eps_setTransform (psim, z1, z2, ztype, offset, slope, cmap_name)
**            eps_setCorners (psim, llx, lly, urx, ury)
**
**	    eps_getImageSize (psim, xdim, ydim, &width, &height)
**	     eps_getImagePos (psim, xdim, ydim, &llx, &llx)
**
**     # Read-only Macro functions:	  Result type
**     ----------------------------	  -----------
** 		 Orientation (psim)	  EPS_PORTRAIT | EPS_LANDSCAPE
** 		       Scale (psim)	  float scale value
** 		    MaxScale (psim)	  float maxaspect scale value
** 		 DoAutoScale (psim)	  bool
** 		DoAutoRotate (psim)	  bool
** 		 DoMaxAspect (psim)	  bool
** 		    PageType (psim)	  EPS_LETTER | EPS_LEGAL | ...
**		    PageXdim (psim)	  page pixel width
**		    PageYdim (psim)	  page pixel height
**		   PageWidth (psim)	  page size in inches
**		  PageHeight (psim)	  page size in inches
**  
**  The first three routines are all that's required to output an array of
**  pixels to an open file descriptor.  The default output produced is a
**  grayscale EPS file, centered in a portrait orientation (unless a rotation
**  is required to make it fit on the page) and auto scaled to fit on a normal
**  8.5"x11" page.
**
**  The remaining routines can be used to set various options, new colormaps
**  labels, etc.  They are not required unless you need to override one or
**  more of the output defaults.
*/

#define	MAX_LENLABEL		256
#define	SZ_EPSBUF		8193

#ifndef AIXV3
#ifndef OSF1
typedef unsigned char 	uchar;
#endif
#endif


static char	*hextab = "0123456789abcdef";
static int	pixnum 	= 0, lpix = 0;
static uchar   *pixbuf;


typedef struct {
	float	sizex, sizey;		/* page size in inches */
	int	npixx, npixy;		/* pix resolution at 72 dpi */
} PSPageInfo;

static PSPageInfo  PageInfo[] = {	/* assumes 300 dpi */
	{ 8.500, 11.000, 		/* US NORMAL, aka LETTER */
	  612, 762
	},
	{ 8.500, 14.000,   		/* US LEGAL */
          612, 1008
	},
	{ 8.267, 11.811,   		/* A4 */
	  595, 850
	},
	{ 7.283, 10.630,   		/* B5 */
	  524, 765
	},
	{11.000, 17.000,   		/* B-size */
          762, 1224
	},
	{ 3.875,  4.875,   		/* 4 by 5 */
	  279, 351
	},
	{ 0.945,  1.417,  		/* 35mm (24x36) */
	  68, 102
	}
};

/* Private procedures. 
*/
static void eps_simpleHeader(), eps_colorHeader();
static void eps_pageParams(), eps_simpleTrailer();
static void eps_writeCmap(), eps_writeTrailer();
static void eps_writeMono(), eps_writePix();
static void eps_writeMonoRGB(), eps_writeRGB();
static void eps_flushPix();
static void eps_annotate(), eps_portLabels(), eps_landLabels();
static void eps_doColorbar();
static float ticstep();
static char *make_label();

static int 	debug = 0;


/*  EPS_INIT -- Allocate and return an initialized pointer to a structure
**  containing the default output setup.
*/
PSImage *
eps_init()
{
	register int i;
	register PSImage *ps;


        /* Allocate the structure. */
	ps = (PSImage *) calloc ((unsigned)1, sizeof (PSImage));

        /* Initialize the structure. */
        ps->cols = 0;
        ps->rows = 0;
        ps->colorClass = EPS_GRAYSCALE;
        ps->compression = NoCompression;
        ps->annotate = 1;
        ps->label = (char *) calloc (MAX_LENLABEL, sizeof (uchar));
	ps->z1 = 0.0;
	ps->z2 = 255.0;
	ps->ztype = 0;

	/* Set up a default grayscale colormap. */
        ps->cmap.ncolors = 256;
        for (i=0; i<ps->cmap.ncolors; i++)
            ps->cmap.r[i] = ps->cmap.g[i] = ps->cmap.b[i] = i;
	ps->cmap.IsDefault = 1;

	/* Load the page information defaults. */
	eps_setPage (ps, EPS_PORTRAIT, EPS_LETTER, 100, EPS_AUTOSCALE);

	/* Initialize the annotation flags */
	ps->page.flags |= (EPS_DOTITLE|EPS_DOBORDERS|EPS_DOCOLORBAR);

	/* Initialize the pixel buffer array */
	pixbuf = (uchar *) calloc (SZ_EPSBUF, sizeof (uchar));

	return (ps);
}


/* EPS_PRINT -- Dump the given array of pixels to the output file as an EPS
** format file.  The data array may contain 8-bit, 24-bit RGB triplets, or
** 32-bit RGBA pixels.  
*/
void
eps_print (psim, fp, data, xdim, ydim, depth, pad)
PSImage *psim;				/* EPS image structure 		     */
FILE	*fp;				/* output file descriptor 	     */
uchar   *data;				/* array of image pixels 	     */
int	xdim, ydim;			/* image dimensions 		     */
int	depth;				/* bits / pixel, must be 8,24, or 32 */
int	pad;				/* bytes per line of padding 	     */
{
	int npix = xdim * ydim;
        uchar *pix = data;


	psim->cols = xdim;		/* save it for the headers */
	psim->rows = ydim;

	if (debug)
	    fprintf (stderr, "eps_print: w=%d h=%d d=%d pad=%d\n",
		xdim, ydim, depth, pad);

        switch (psim->colorClass) {
        case EPS_GRAYSCALE:
	    /* Regardless of the color type desired we'll either write the
	     * pixels directly or convert from pseudocolor or RGB.  For a
	     * start dump the header. 
	     */
	    eps_simpleHeader (psim, fp);

	    if (psim->cmap.IsDefault && depth == 8) {
		/* We're using the default grayscale colormap with an 
		 * 8-bit image, so just dump the pixels.
		 */
	        if (debug)
	 	    fprintf (stderr,"eps_print: straight grayscale.\n");
		eps_writePix (fp, pix, &psim->cmap, npix, xdim, pad);

	    } else if (!psim->cmap.IsDefault && depth == 8) {
		/* We're using an arbitrary colormap with an 8-bit image, 
	   	 * so convert to grayscale and write the pixels.
		 */
	        if (debug)
		    fprintf (stderr,"eps_print: pseudo cnv to grayscale.\n");
		eps_writeMono (fp, pix, &psim->cmap, npix, xdim, pad);

	    } else {
                /* Convert RGBA to grayscale. */
	        if (debug)
		    fprintf (stderr,"eps_print: RGB cnv to grayscale.\n");
		eps_writeMonoRGB (fp, pix, npix, xdim, depth, pad);

	    }

	    /* Now that the image is out we restore the graphics context. */
            fprintf (fp, "grestore\n" );

	    /* Write the colorbar. */
	    if (psim->annotate)
	        eps_annotate (psim, fp);

	    /* Write the trailer. */
	    eps_simpleTrailer (fp);
            break;

        case EPS_PSEUDOCOLOR:
	    /* Write the color prolog header. */
	    eps_colorHeader (psim, fp);

	    /* Dump the colormap. */
            eps_writeCmap (&psim->cmap, fp);

            /* Write color indices. */
	    eps_writePix (fp, pix, &psim->cmap, npix, xdim, pad);

	    /* Write the colorbar. */
	    if (psim->annotate)
	        eps_annotate (psim, fp);

	    /* Write the trailer to finish it off. */
	    eps_writeTrailer (fp);
            break;

        case EPS_TRUECOLOR:
            /* Write the seudocolor prolog header. */
            eps_colorHeader (psim, fp);

	    eps_writeRGB (fp, pix, &psim->cmap, npix, xdim, depth, pad);

	    /* Write the colorbar. */
	    if (psim->annotate)
	        eps_annotate (psim, fp);

	    /* Write the trailer to finish it off. */
	    eps_writeTrailer (fp);
            break;

        default:
            perror ("Bad colorClass specification.\n");
            break;
        }

	fflush (fp);
}


/* EPS_CLOSE -- Close down the EPS output structure.
*/
void
eps_close (psim)
PSImage *psim;				/* EPS image structure */
{
	if (psim->label)
	    (void) free ((char *) psim->label);
	(void) free ((char *) pixbuf);
	(void) free (psim);
}


/* EPS_SETPAGE -- Inialize the page setup with a different size, orientation,
** or scale options.
*/
void
eps_setPage (psim, orientation, paper_size, scale, flags)
PSImage *psim;				/* EPS image structure 		     */
int	orientation;			/* page orientation flag 	     */
int	paper_size;			/* paper size flag 		     */
int	scale;				/* image scale percentage 	     */
int	flags;				/* option flags 		     */
{
	int NPageTypes = sizeof (PageInfo) / sizeof (PSPageInfo);


	/* Set the orientation of the output */
	if (orientation == EPS_PORTRAIT)
            psim->page.orientation = EPS_PORTRAIT;
	else if (orientation == EPS_LANDSCAPE)
            psim->page.orientation = EPS_LANDSCAPE;
	else 
	    perror ("eps_setPage: Invalid orientation.");

	/* Set the output paper size */
	if (paper_size >= 0 && paper_size <= NPageTypes)
            psim->page.page_type = paper_size;
	else 
	    perror ("eps_setPage: Invalid paper size.");

	/* Set scale and recompute dpi resolution. */
        psim->page.scale = (float) scale / 100.0;
        psim->page.maxscale = (float) scale / 100.0;
        psim->page.dpi = 72;			/* need to recalculate */

	/* Set the option flags */
        psim->page.flags = flags;

	if (debug) {
	    fprintf (stderr,
		"eps_setPage: orientation:%d size:%d scale:%g\n",
	        Orientation(psim), PageType(psim), Scale(psim));
	    fprintf (stderr,"\tautoscale:%d autorotate:%d maxaspect:%d\n",
	        DoAutoScale(psim), DoAutoRotate(psim), DoMaxAspect(psim));
	}
}


/* EPS_SETCMAP -- Define a given colormap to be used on output.
*/
void
eps_setCmap (psim, r, g, b, ncolors)
PSImage *psim;				/* EPS image structure 		     */
uchar *r, *g, *b;			/* color components 		     */
int ncolors;				/* number of colors in colormap      */
{
	register int i = 0;

	/* Load the colormap. */
	psim->cmap.ncolors = ncolors;
	/* for (i=0;  i < ncolors;  i++) { */
	for (i=0;  i < 256;  i++) {
	    psim->cmap.r[i] = r[i];
	    psim->cmap.g[i] = g[i];
	    psim->cmap.b[i] = b[i];
	}

	psim->cmap.IsDefault = 0;
}


/* EPS_SETCOMPRESS -- Define the type of output compression to use.
*/
void
eps_setCompress (psim, compress)
PSImage *psim;				/* EPS image structure 		     */
int	compress;			/* compression type flag 	     */
{
	/* Set the compression type to use. */
	switch (compress) {
	case NoCompression:
	case RLECompression:
	    psim->compression = compress;
	    break;
	case LZWCompression:
	case JPEGCompression:
	default:
	    perror ("eps_setCompress: Invalid compression type.");
	}
}


/* EPS_SETCOLORTYPE -- Set the type of output image to be written, e.g. even
** though we have an RGB or pseudocolor image we may wish to coerce it to 
** a grayscale on output.
*/
void
eps_setColorType (psim, color_class)
PSImage *psim;				/* EPS image structure 		     */
int	color_class;			/* output color class 		     */
{
	/* Set the compression type to use. */
	switch (color_class) {
	case EPS_GRAYSCALE:
	case EPS_PSEUDOCOLOR:
	case EPS_TRUECOLOR:
	    psim->colorClass = color_class;
	    break;
	default:
	    perror ("eps_setColorType: Invalid output color type.");
	}
}


/* EPS_SETLABEL -- Set the output label to be used in annotation.
*/
void
eps_setLabel (psim, label)
register PSImage *psim;			/* EPS image structure 		     */
char	*label;				/* Label string 		     */
{
	register int maxlen = MAX_LENLABEL;

	if (!psim->label)
	    psim->label = (char *) malloc (maxlen);

	if (psim->page.flags & EPS_DOTITLE) {
	    (void) strncpy (psim->label, label, maxlen-1);
	    psim->label[maxlen-1] = '\0';
	} else
	    psim->label[0] = '\0';
}


/* EPS_SETTRANSFORM -- Set the color transformation parameters, i.e. the
** z1/z2 values that map the image pixel values being displayed to the number
** of colors we have available.  This is used in the annotation when labeling
** the colorbar.
*/
void
eps_setTransform (psim, z1, z2, ztype, offset, scale, cmap_name)
PSImage *psim;                          /* EPS image structure  	     */
float	z1, z2;				/* zscale values 		     */
int	ztype;				/* Transformation type  	     */
float	offset, scale;			/* brightness/contrast values 	     */
char	*cmap_name;			/* colormap name		     */
{
        psim->z1 = z1;
        psim->z2 = z2;
        psim->ztype = ztype;
        psim->offset = offset;
        psim->scale = scale;
	if (!psim->cmap.cmap_name)
	    psim->cmap.cmap_name = (char *) malloc (16);
	strcpy (psim->cmap.cmap_name, cmap_name);

	if (debug) {
	    fprintf (stderr, 
	       "setTransform: z1=%g z2=%g zt=%d offset=%g scale=%g name='%s'\n",
		psim->z1, psim->z2, psim->ztype, 
		psim->offset, psim->scale,
		psim->cmap.cmap_name);
	}
}


/* EPS_SETCORNERS -- Set the image corner values.
*/
void
eps_setCorners (psim, llx, lly, urx, ury)
PSImage *psim;                          /* EPS image structure  	     */
int	llx, lly, urx, ury;		/* image corners		     */
{
	psim->llx = llx;
	psim->lly = lly;
	psim->urx = urx;
	psim->ury = ury;
}


/* EPS_GETIMAGESIZE -- Given the current page parameters and image dimensions,
** compute the size of the image (in inches) on the page.
*/       
void
eps_getImageSize (psim, xdim, ydim, width, height)
PSImagePtr psim;			/* EPS image struct 		     */
int	xdim, ydim;			/* image dimensions 		     */
float	*width, *height;		/* width x height of image on page   */
{
        int icols, irows, scols, srows, turnflag;
	float	llx, lly;


        /* Get the common page parameters. */
        eps_pageParams (psim, &llx, &lly, &icols, &irows, &scols, &srows,
	    &turnflag);

	*width = (scols / (float) psim->page.dpi);
	*height = (srows / (float) psim->page.dpi);
}


/* EPS_GETIMAGEPOS -- Given the current page parameters and image dimensions,
** compute the position of the image (in pixels) on the page.
*/	        
void
eps_getImagePos (psim, xdim, ydim, llx, lly)
PSImagePtr psim;			/* EPS image struct 		     */
int	xdim, ydim;			/* image dimensions 		     */
int	*llx, *lly;			/* LL coords for centered image      */
{
        int icols, irows, scols, srows, turnflag;
	float	lx, ly;


        /* Get the common page parameters. */
        eps_pageParams (psim, &lx, &ly, &icols, &irows, &scols, &srows,
	    &turnflag);

	*llx = (int) lx;
	*lly = (int) ly;
}


/************************
 *  Private Procedures  *
 ************************/


/* EPS_PAGEPARAMS -- Compute the EPS page parameters.
*/
static void 
eps_pageParams (psim, llx, lly, icols, irows, scols, srows, turnflag)
PSImagePtr psim;			/* EPS image struct 		     */
float	*llx, *lly;			/* LL coords for centered image      */
int	*icols, *irows;			/* final image rows/cols 	     */
int	*scols, *srows;			/* scaled rows/cols 		     */
int	*turnflag;			/* turn the image? 		     */
{
        int devpix, pwidth, pheight, cols=0, rows=0;
        float pixfac, scale = Scale(psim), margin;


        /* See if we need to rotate the image to fit on the page. */
	margin = (psim->annotate ? 0.9 : 0.95);
	pwidth = (int) PageXdim(psim) * margin;
	pheight = (int) PageYdim(psim) * margin;
        *icols = cols = psim->cols;
        *irows = rows = psim->rows;
        *turnflag = 0;
        if (DoAutoRotate(psim)) {
            if (psim->cols > psim->rows && (scale * psim->cols) > pwidth) {
	        if (debug) fprintf (stderr, "Rotating image....\n");
                *turnflag = 1;
                cols = *irows;
                rows = *icols;
	    }
        } else if (psim->page.orientation == EPS_LANDSCAPE) {
	        if (debug) fprintf (stderr, "Rotating image....\n");
                *turnflag = 1;
                cols = *irows;
                rows = *icols;
        }
	
	if (turnflag) {
	    margin = (turnflag ? 0.825 : margin);
	    pwidth = (int) PageXdim(psim) * margin;
	    pheight = (int) PageYdim(psim) * margin;
	}

        /* Figure out the image size. */
        devpix = psim->page.dpi / 72.0 + 0.5;      /* device pixels per unit */
        pixfac = 72.0 / psim->page.dpi * devpix;
        *scols = psim->page.scale * cols * pixfac;
        *srows = psim->page.scale * rows * pixfac;

        /* See if we need to fiddle with the size to get it on the page
	 * the way we want.
	 */
	if (debug) {
	    fprintf (stderr, "before: scale=%g scols=%d srows=%d pixfac=%g\n",
		scale, *scols, *srows, pixfac);
	    fprintf (stderr, "\tpwidth=%d pheight=%d\n", pwidth, pheight);
	    fprintf (stderr,"\tautoscale:%d autorotate:%d maxaspect:%d\n",
	        DoAutoScale(psim), DoAutoRotate(psim), DoMaxAspect(psim));
	}
        if ( *scols > pwidth || *srows > pheight ) {

	    /* Image is larger than we think will fit on the page. If we're
	     * autoscaling reset the scale.
	     */
            if (DoAutoScale(psim)) {
	        if (debug)
		    fprintf (stderr, "Image too big, autoscaling...\n");
                if ( *scols >= pwidth ) {
		    if (*scols >= *srows) {
                        scale *= (float)PageXdim(psim) / (float)*scols * margin;
                        *scols = scale * cols * pixfac;
                        *srows = scale * rows * pixfac;
		    } else {
                        scale *= (float)PageYdim(psim) / (float)*srows * margin;
                        *scols = scale * cols * pixfac;
                        *srows = scale * rows * pixfac;
		    }
                }
	        if (debug)
		    fprintf (stderr, ": scale=%f scols=%d srows=%d pixfac=%g\n",
			scale, *scols, *srows, pixfac);
                if ( *srows >= pheight ) {
		    if (*scols >= *srows) {
                        scale *= (float)PageXdim(psim) / (float)*scols * margin;
                        *scols = scale * cols * pixfac;
                        *srows = scale * rows * pixfac;
		    } else {
                        scale *= (float)PageYdim(psim) / (float)*srows * margin;
                        *scols = scale * cols * pixfac;
                        *srows = scale * rows * pixfac;
		    }
                }
	        if (debug)
		    fprintf (stderr, ": scale=%f scols=%d srows=%d pixfac=%g\n",
			scale, *scols, *srows, pixfac);
	        psim->page.maxscale = scale; 	/* update new scale factor */

            } else {
		/* Notify user that the image won't fit and suggest a scale. */
                if ( *scols > pwidth )
                    scale *= (float) PageXdim(psim) / (float) *scols * margin;
                if ( *srows > pheight )
                    scale *= (float) PageYdim(psim) / (float) *srows * margin;
	        psim->page.maxscale = scale; 	/* update new scale factor */

		fprintf (stderr, 
		    "Image too big for the page, no autoscaling set...\n");
		fprintf (stderr, "Reset autoscale flag or use scale < %g\n",
		    scale);
	    }

        } 

	if (DoMaxAspect(psim)) {
	    /* Image will fit on page, but blow it up to a maximum size for
	     * the page orientation but retain the image aspect.
	     */
	    if (debug)
		fprintf (stderr, "Doing max aspect...");
	    if ( *scols >= *srows ) {
                scale *= (float) PageXdim(psim) / (float) *scols * margin;
                *scols = scale * cols * pixfac;
                *srows = scale * rows * pixfac;
	    } else if ( *srows > *scols ) {
                scale *= (float) PageYdim(psim) / (float) *srows * margin;
                *scols = scale * cols * pixfac;
                *srows = scale * rows * pixfac;
	    }
	    psim->page.maxscale = scale; 	/* update new scale factor */
	}

        /* Center it on the page. */
        *llx = (PageXdim(psim) - *scols) / 2 - (*turnflag ? 10 : 0);
        *lly = (PageYdim(psim) - *srows) / 2 + (*turnflag ? 0 : 10);

	if (debug) {
	    fprintf(stderr,"after: scale=%g scols=%d srows=%d ",
		scale, *scols, *srows);
	    fprintf(stderr,"icols=%d irows=%d llx=%g lly=%g\n",
		*icols, *irows, *llx, *lly);
	}
}


/* EPS_WRITEPIX -- Write the pixels or color indices directly.
*/
static void
eps_writePix (fp, pix, cmap, npix, xdim, pad)
FILE    *fp;
uchar   *pix;
PSCmap 	*cmap;
int     npix;
int     xdim;
int     pad;
{
        register int i, min, max;


	min = *pix;
	max = *pix;
        while (npix > 0) {
	    min = (min > *pix ? *pix : min);
	    max = (max < *pix ? *pix : max);

            /* Write the pixels. */
	    for (i=0; i < PIX_PER_LINE && npix--; i+=2) {
        	pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix >> 4)]; 
        	pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix++ & 0x0F)]; 
	    }
            pixbuf[pixnum++] = '\n';

            if (pixnum >= (SZ_EPSBUF - PIX_PER_LINE - 1)) {
                pixbuf[pixnum] = '\0';
                fwrite ((char *)pixbuf, sizeof(char), pixnum, fp);
                pixnum = 0;
            }
            
            /* Skip the pad chars. */
            for (i=0; i<pad && npix; i++, npix--)
                pix++;
        }
	cmap->min = min; 
	cmap->max = max;
	eps_flushPix (fp);
}


/* EPS_WRITEMONO -- Write a pseudocolor image and convert to grayscale.
*/
static void
eps_writeMono (fp, pix, cmap, npix, xdim, pad)
FILE	*fp;
uchar   *pix;
PSCmap 	*cmap;
int 	npix;
int	xdim;
int	pad;
{
	register int i, min, max;
	register uchar pval;

	min = *pix;
	max = *pix;
        while (npix > 0) {
	    min = (min > *pix ? *pix : min);
	    max = (max < *pix ? *pix : max);

            /* Write the pixels. */
            for (i=0; i < PIX_PER_LINE && npix; i+=2, npix-- ) {
                pval = (uchar) MONO (cmap->r[*pix], 
				     cmap->g[*pix],
                                     cmap->b[*pix++]);
                pixbuf[pixnum++] = (uchar) hextab[(pval >> 4)];
                pixbuf[pixnum++] = (uchar) hextab[(pval & 0x0F)];
            }
            pixbuf[pixnum++] = '\n';

            if (pixnum >= (SZ_EPSBUF - PIX_PER_LINE - 1) || !npix) {
                pixbuf[pixnum] = '\0';
                fwrite ((char *)pixbuf, sizeof(char), pixnum, fp);
                pixnum = 0;
            }

            /* skip the pad chars */
            for (i=0; i<pad && npix; i++, npix--)
                pix++;
        }
	cmap->min = min; 
	cmap->max = max;
	eps_flushPix (fp);
}


/* EPS_WRITEMONORGB --  Write RGB data converted to grayscale.
*/
static void
eps_writeMonoRGB (fp, pix, npix, xdim, depth, pad)
FILE    *fp;
uchar   *pix;
int     npix;
int     xdim;
int     depth;
int     pad;
{
        register int i;
	register uchar pval;


        while (npix > 0) {
            /* Write the pixels. */
	    if (depth < 24) {
                for (i=0; i < PIX_PER_LINE && npix; i+=2, npix-=3 ) {
                    pval = (uchar) MONO (*pix++, *pix++, *pix++);
                    pixbuf[pixnum++] = (uchar) hextab[(pval >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[(pval & 0x0F)];
                }
            } else {
		/* Skip alpha channel in the loop */
                for (i=0; i < PIX_PER_LINE && npix; i+=2, npix-=3, pix++ ) {
                    pval = (uchar) MONO (*pix++, *pix++, *pix++);
                    pixbuf[pixnum++] = (uchar) hextab[(pval >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[(pval & 0x0F)];
                }
            }
            pixbuf[pixnum++] = '\n';

            if (pixnum >= (SZ_EPSBUF - PIX_PER_LINE - 1)) {
                pixbuf[pixnum] = '\0';
                fwrite ((char *)pixbuf, sizeof(char), pixnum, fp);
                pixnum = 0;
            }

            /* skip the pad chars */
            for (i=0; i<pad && npix; i++, npix--)
                pix++;
        }
	eps_flushPix (fp);
}


/* EPS_WRITERGB -- Write the pixels in RGB format, skipping a possible alpha
** channel.
*/
static void
eps_writeRGB (fp, pix, cmap, npix, xdim, depth, pad)
FILE    *fp;
uchar   *pix;
PSCmap 	*cmap;
int     npix;
int     xdim;
int     depth;
int     pad;
{
        register int i, min, max;
	register uchar val;


        min = *pix;
        max = *pix;
        while (npix > 0) {
            min = (min > *pix ? *pix : min);
            max = (max < *pix ? *pix : max);

            /* Write the pixels. */
            if (depth < 24) {
                for (i=0; i < PIX_PER_LINE && npix; i+=6, npix--, pix++ ) {
                    val = (uchar) cmap->r[*pix];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)val >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)val & 0x0F)];
                    val = (uchar) cmap->g[*pix];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)val >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)val & 0x0F)];
                    val = (uchar) cmap->b[*pix];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)val >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)val & 0x0F)];
                }
            } else {
                /* Skip alpha channel in the loop */
                for (i=0; i < PIX_PER_LINE && npix; i+=6, npix-=3, pix++ ) {
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix++ & 0x0F)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix++ & 0x0F)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix >> 4)];
                    pixbuf[pixnum++] = (uchar) hextab[((uchar)*pix++ & 0x0F)];
                }
            }
            pixbuf[pixnum++] = '\n';

            if (pixnum >= (SZ_EPSBUF - PIX_PER_LINE - 1)) {
                pixbuf[pixnum] = '\0';
                fwrite ((char *)pixbuf, sizeof(char), pixnum, fp);
                pixnum = 0;
            }


            /* skip the pad chars */
            for (i=0; i<pad && npix; i++, npix--)
                pix++;
        }
	cmap->min = min; 
	cmap->max = max;
	eps_flushPix (fp);
}


/* EPS_WRITECMAP -- Output Postscript colormap.
*/
static void
eps_writeCmap (cmap, fp)
PSCmap 	*cmap;
FILE	*fp;
{
	register int i, j;

	/* Dump number of colors and colormap used. */
       	fprintf (fp, "256\n");
      	for (i=0; i < 256; ) {
      	    for (j=0; j < 10 && i < 256; i++, j++) {
                fprintf (fp, "%02x%02x%02x", 
		    cmap->r[i], cmap->g[i], cmap->b[i]);
	    }
            fprintf (fp, "\n");
	}
}


/* EPS_SIMPLEHEADER -- Output simple Postscript header.
*/
static char *EPSSimpleRLEProlog[]= {
        "/rlestr1 1 string def\n",  
        "/readrlestring {                      		/* s -- nr */\n",
        "  /rlestr exch def                    		/* - */\n",
        "  currentfile rlestr1 readhexstring pop        /* s1 */\n",
        "  0 get                               		/* c */\n",
        "  dup 127 le {                        		/* c */\n",
        "    currentfile rlestr 0              		/* c f s 0 */\n",
        "    4 3 roll                          		/* f s 0 c */\n",
        "    1 add  getinterval                		/* f s */\n",
        "    readhexstring pop                 		/* s */\n",
        "    length                            		/* nr */\n",
        "  } {                                 		/* c */\n",
        "    256 exch sub dup                  		/* n n */\n",
        "    currentfile rlestr1 readhexstring pop     	/* n n s1 */\n",
        "    0 get                             		/* n n c */\n",
        "    exch 0 exch 1 exch 1 sub {        		/* n c 0 1 n-1*/\n",
        "      rlestr exch 2 index put\n",  
        "    } for                             		/* n c */\n",
        "    pop                               		/* nr */\n",
        "  } ifelse                            		/* nr */\n",
        "} bind def\n",  
        "/readstring {                         		/* s -- s */\n",
        "  dup length 0 {                      		/* s l 0 */\n",
        "    3 copy exch                       		/* s l n s n l*/\n",
        "    1 index sub                       		/* s l n s n r*/\n",
        "    getinterval                       		/* s l n ss */\n",
        "    readrlestring                     		/* s l n nr */\n",
        "    add                               		/* s l n */\n",
        "    2 copy le { exit } if             		/* s l n */\n",
        "  } loop                              		/* s l l */\n",
        "  pop pop                             		/* s */\n",
        "} bind def\n",  
      	NULL
};

static void
eps_simpleHeader (psim, fp)
PSImagePtr psim;
FILE	   *fp;
{
        register char **line;
        int 	icols=0, irows=0, scols=0, srows=0, turnflag=0;
        float 	llx = 0.0, lly = 0.0;
        time_t  timer;


        /* Get the common page parameters. */
        eps_pageParams (psim, &llx, &lly, &icols, &irows, &scols, &srows,
	    &turnflag);

	/* Now write header and prolog stuff */
        fprintf (fp, "%%!PS-Adobe-3.0 EPSF-3.0\n" );
	fprintf (fp, "%%%%Title: XImtool Screen Hardcopy\n");
	fprintf (fp, "%%%%Creator: XImtool\n");
  	timer = time ((time_t *) NULL);
	(void) localtime (&timer);
	fprintf (fp, "%%%%CreationDate: %s", ctime(&timer));
        if (psim->annotate)
            fprintf (fp, "%%%%BoundingBox: %d %d %d %d\n",
                (int) (MAX (0, llx - X_ANNOT_MARGIN)),
                (int) (MAX (0, lly - Y_ANNOT_MARGIN)),
                (int) ( llx + scols + 0.5 + X_ANNOT_MARGIN),
                (int) ( lly + srows + 0.5 + Y_ANNOT_MARGIN) );
        else
            fprintf (fp, "%%%%BoundingBox: %d %d %d %d\n",
                (int) (MAX (0, llx - 10)),
                (int) (MAX (0, lly - 10)),
                (int) ( llx + scols + 0.5 + 10),
                (int) ( lly + srows + 0.5 + 10) );
	fprintf (fp, "%%%%Pages: 1\n");
        fprintf (fp, "%%%%EndComments\n" );

    	if ( psim->compression == RLECompression ) {
            for (line = EPSSimpleRLEProlog; *line; line++)
                fprintf (fp, "%s\n",*line);
        } else {
            fprintf (fp, "/readstring {\n" );                    /* s -- s */
            fprintf (fp, "  currentfile exch readhexstring pop\n" );
            fprintf (fp, "} bind def\n" );
        }

    	if (psim->colorClass == EPS_TRUECOLOR) {
            fprintf (fp, "/rpicstr %d string def\n", icols );
            fprintf (fp, "/gpicstr %d string def\n", icols );
            fprintf (fp, "/bpicstr %d string def\n", icols );
        } else
            fprintf (fp, "/picstr %d string def\n", icols );
        fprintf (fp, "%%%%EndProlog\n" );
        fprintf (fp, "%%%%Page: 1 1\n" );
        fprintf (fp, "gsave\n" );

        fprintf (fp, "%g %g translate\n", llx, lly );
        fprintf (fp, "%d %d scale\n", scols, srows );
    	if ( turnflag ) {
	    if (debug) fprintf (stderr, "turnflag enabled....\n");
            fprintf (fp, "0.5 0.5 translate  90 rotate  -0.5 -0.5 translate\n");
	}
        fprintf (fp, "%d %d 8\n", icols, irows);
        fprintf (fp, "[ %d 0 0 -%d 0 %d ]\n", icols, irows, irows );

    	if (psim->colorClass == EPS_TRUECOLOR) {
            fprintf (fp, "{ rpicstr readstring }\n" );
            fprintf (fp, "{ gpicstr readstring }\n" );
            fprintf (fp, "{ bpicstr readstring }\n" );
            fprintf (fp, "true 3\n" );
            fprintf (fp, "colorimage\n" );
        } else {
            fprintf (fp, "{ picstr readstring }\n" );
            fprintf (fp, "image\n" );
        }
}


/* EPS_ANNOTATE --  Annotate the main image window with axis labels,
** colorbars, and the title string.
*/

static void
eps_annotate (psim, fp)
PSImagePtr psim;
FILE       *fp;
{
        int     icols=0, irows=0, scols=0, srows=0, turnflag=0;
	int	cbar_size;
        float   llx = 0.0, lly = 0.0;


        /* Get the common page parameters. */
        eps_pageParams (psim, &llx, &lly, &icols, &irows, &scols, &srows,
            &turnflag);

	/* Main image title. */
	if (psim->label != NULL && (psim->page.flags & EPS_DOTITLE)) {
	    /* Write the annotation prolog stufd. */
            fprintf (fp, "gsave\n" );

            fprintf (fp, 
	      "/labelfont /NewCenturySchlbk-Roman findfont 16 scalefont def\n");
	    if (turnflag) {
                fprintf (fp, "/label { moveto labelfont setfont\n");
	     	fprintf (fp, "         90 rotate show -90 rotate\n} def\n" );
      	        fprintf (fp, "(%s) %g %g label\n", psim->label,
	            llx - TITLE_OFFSET,
	            lly + (srows/2) - 8.25*(strlen(psim->label)/2) );
	    } else {
                fprintf (fp, "/label { moveto labelfont setfont show } def\n" );
      	        fprintf (fp, "(%s) %g %g label\n", psim->label,
	            llx + (scols/2) - 8.25*(strlen(psim->label)/2), 
		    lly + srows + TITLE_OFFSET);
	    }
            fprintf (fp, "grestore\n");
	}

	/* A border for the image axes. */
	if (psim->page.flags & EPS_DOBORDERS) {
            fprintf (fp, "gsave\n" );
	    fprintf (fp, "/imBorder {\n");
	    fprintf (fp, "   %-4d %-4d moveto	%% Outer axis\n", 
	        (int)(llx - AXIS_OOFFSET), 
	        (int)(lly - AXIS_OOFFSET));
	    fprintf (fp, "   0    %-4d rlineto\n", srows + (2 * AXIS_OOFFSET));
	    fprintf (fp, "   %-4d  0 rlineto\n", scols + (2 * AXIS_OOFFSET));
	    fprintf (fp, "   0  -%-4d rlineto\n", srows + (2 * AXIS_OOFFSET));
	    fprintf (fp, "   closepath\n");
	    fprintf (fp, "   %g setlinewidth\n", AXIS_OWIDTH);
	    fprintf (fp, "   stroke\n");

	    fprintf (fp, "   %-4d %-4d moveto	%% Inner axis\n", 
	        (int)(llx - AXIS_IOFFSET), 
	        (int)(lly - AXIS_IOFFSET));
	    fprintf (fp, "   0   %-4d rlineto\n", srows + (2 * AXIS_IOFFSET));
	    fprintf (fp, "   %-4d  0 rlineto\n", scols + (2 * AXIS_IOFFSET));
	    fprintf (fp, "   0   -%-4d rlineto\n", srows + (2 * AXIS_IOFFSET));
	    fprintf (fp, "   closepath\n");
	    fprintf (fp, "   %g setlinewidth\n", AXIS_IWIDTH);
	    fprintf (fp, "   stroke\n");

	    fprintf (fp, "} def\n");
	    fprintf (fp, "imBorder\n");

	    /* Axis label font definitions. */
	    fprintf (fp,"/axlabelfont /Times-Roman findfont 8 scalefont def\n");
	    fprintf (fp,
		"/axlabel { moveto axlabelfont setfont %s show %s } def\n",
	        (turnflag ? "90 rotate" : " "),
	        (turnflag ? "-90 rotate" : " "));

	    /* Axis ticmark procedures. */
	    fprintf (fp, "/xMajorTicmark {\n");
	    fprintf (fp, "    moveto\n");
	    fprintf (fp, "    0 %d rlineto    ", MAJOR_TICK_SIZE);
	    fprintf (fp, "    0 %d rmoveto    ", 
	        srows + MAJOR_TICK_SIZE + (2 * AXIS_IOFFSET) );
	    fprintf (fp, "    0 -%d rlineto\n", MAJOR_TICK_SIZE);
	    fprintf (fp, "    %g setlinewidth\n    stroke\n", MAJOR_TICK_WIDTH);
	    fprintf (fp, "} def\n");
	    fprintf (fp, "/yMajorTicmark {\n");
	    fprintf (fp, "    moveto\n");
	    fprintf (fp, "    %d 0 rlineto    ", MAJOR_TICK_SIZE);
	    fprintf (fp, "    %d 0 rmoveto    ", 
	        scols + MAJOR_TICK_SIZE + (2 * AXIS_IOFFSET) );
	    fprintf (fp, "    -%d 0 rlineto\n", MAJOR_TICK_SIZE);
	    fprintf (fp, "    %g setlinewidth\n    stroke\n", MAJOR_TICK_WIDTH);
	    fprintf (fp, "} def\n");
	    fprintf (fp, "/xMinorTicmark {\n");
	    fprintf (fp, "    moveto\n");
	    fprintf (fp, "    0 %d rlineto    ", MINOR_TICK_SIZE);
	    fprintf (fp, "    0 %d rmoveto    ", 
	        srows + MAJOR_TICK_SIZE + (2*AXIS_IOFFSET) +
	        (MAJOR_TICK_SIZE - MINOR_TICK_SIZE) );
	    fprintf (fp, "    0 -%d rlineto\n", MINOR_TICK_SIZE);
	    fprintf (fp, "    %g setlinewidth\n    stroke\n", MINOR_TICK_WIDTH);
	    fprintf (fp, "} def\n");
	    fprintf (fp, "/yMinorTicmark {\n");
	    fprintf (fp, "    moveto\n");
	    fprintf (fp, "    %d 0 rlineto    ", MINOR_TICK_SIZE);
	    fprintf (fp, "    %d 0 rmoveto    ", 
	        scols + MAJOR_TICK_SIZE + (2*AXIS_IOFFSET) + 
	        (MAJOR_TICK_SIZE - MINOR_TICK_SIZE) );
	    fprintf (fp, "    -%d 0 rlineto\n", MINOR_TICK_SIZE);
	    fprintf (fp, "    %g setlinewidth\n    stroke\n", MINOR_TICK_WIDTH);
	    fprintf (fp, "} def\n");

	    /* The axis labeling.  */
	    if (turnflag)
	        eps_landLabels (fp, psim, scols, srows, icols, irows, llx, lly);
	    else
	        eps_portLabels (fp, psim, scols, srows, icols, irows, llx, lly);
            fprintf (fp, "grestore\n");
	}

	/* The colorbar.  */
	if (psim->page.flags & EPS_DOCOLORBAR) {
    	    eps_doColorbar (fp, psim, scols, srows, llx, lly, turnflag);

	    /* Print the transform information.  */
            fprintf (fp, "gsave\n");
	    fprintf (fp, "/Times-Roman findfont 8 scalefont setfont\n");
	    if (turnflag) {
                cbar_size = MIN (512, MAX (256, srows + 2));
                fprintf (fp, "%d %d moveto\n", 
		    (int)llx + scols + 26, 
		    (int)lly + (srows/2) - (cbar_size/2)-(cbar_size==256?5:1));
	    } else {
                cbar_size = MIN (512, MAX (256, scols + 2));
                fprintf (fp, "%d %d moveto\n", 
		    (int)llx + (scols/2) - (cbar_size/2)-(cbar_size==256?5:1),
		    (int)(lly-29));
	    }
	    fprintf (fp, "(z1=%.2f z2=%.2f ztrans=%s Con=%.2f Brt=%.2f cmap=%s ncolors=%d) %s show %s\n",
	        psim->z1, psim->z2,
	        (psim->ztype==EPS_UNITARY ? "unitary": 
		    (psim->ztype==EPS_LINEAR ? "linear" : "log")),
	        psim->scale, psim->offset,
	        psim->cmap.cmap_name,
	        psim->cmap.max - psim->cmap.min + 1,
	        (turnflag ? "90 rotate" : " "),
	        (turnflag ? "-90 rotate" : " "));
            fprintf (fp, "grestore\n");
	}

	/* Print the timestamp. */
        fprintf (fp, "gsave\n");
        fprintf (fp, "/Times-Roman findfont 6 scalefont setfont\n");
        fprintf (fp, "20 15 moveto\n(%s) show\n", make_label());
	fprintf (fp, "grestore\n");

	if (debug) { 
	    fprintf (stderr, "colormap: min/max = %d/%d\n", 
		psim->cmap.min, psim->cmap.max);
	    fprintf (stderr, "label: '%s'", make_label());
	}
}


/* EPS_PORTRAITLABELS -- Write out the labeling procedures for a portrait
** mode image.
*/

static void 
eps_portLabels (fp, psim, scols, srows, icols, irows, llx, lly)
FILE	*fp;
PSImagePtr psim;
int	scols, srows;
int	icols, irows;
float	llx, lly;
{
	int	start, end, range;
	float 	xpos, xstep, ypos, ystep;
        float   Mval, xval=0.0, yval=0.0, tic, mtic, Mtic;


	/* X Axis labeling and ticmarks. 
	*/
        fprintf (fp, "/axLabelX {\n");
	if (psim->urx > psim->llx) {
	    start = psim->llx;
	    end = psim->urx;
	} else {
	    start = psim->urx;
	    end = psim->llx;
	}
	range = end - start + 1;
	Mtic = tic = ticstep ((float)range, (range>=256 ? NTICMARKS : 3));
	mtic = (float) tic / (tic < 100 ? 5. : 10.);
	Mval = ( (int)(start + Mtic) / (int) Mtic) * Mtic;
	xval = ( (int)(start + mtic) / (int) mtic) * mtic;
	xstep = mtic * ((float)scols/(float)(range));
	if (psim->urx > psim->llx) 
	    xpos = llx + ( (float)(xval - start) / (float)range * scols);
	else {
	    xpos = (llx + scols) - ((float)(xval-start) / (float)range * scols);
	    xstep = -xstep;
	}
	while (xval <= end) {
	    if ( xval == Mval ) {
	        fprintf (fp, "    %4d %4d xMajorTicmark\t", 
		    (int)xpos, (int)(lly-AXIS_OOFFSET));
	        fprintf (fp, "    (%g) %d %d axlabel\n", 
		    xval,
		    (int)xpos-(xval>=1000?8:(xval>=100?5:2)),
		    (int)(lly-14));
	        Mval += Mtic;
	    } else
	        fprintf (fp, "\t%4d %4d xMinorTicmark\n", 
		    (int)xpos, (int)(lly-AXIS_OOFFSET));
	    xval += mtic;
	    xpos += xstep;
	}
        fprintf (fp, "} def\n");
        fprintf (fp, "axLabelX\n");

	/* Y Axis labeling and ticmarks. */
        fprintf (fp, "/axLabelY {\n");
	if (psim->ury > psim->lly) {
	    start = psim->lly;
	    end = psim->ury;
	} else {
	    start = psim->ury;
	    end = psim->lly;
	}
	range = end - start + 1;
	Mtic = tic = ticstep ((float)range, (range>=256 ? NTICMARKS : 3));
	mtic = (float) tic / (tic < 100 ? 5. : 10.);
	Mval = ( (int)(start + Mtic) / (int) Mtic) * Mtic;
	yval = ( (int)(start + mtic) / (int) mtic) * mtic;
	ystep = mtic * ((float)srows/(float)(range));
	if (psim->ury > psim->lly) 
	    ypos = lly + ( (float)(yval - start) / (float)range * srows);
	else {
	    ypos = (lly + srows) - ((float)(yval-start) / (float)range * srows);
	    ystep = -ystep;
	}
	while (yval <= end) {
	    if ( yval == Mval ) {
	        fprintf (fp, "    %4d %4d yMajorTicmark\t", 
		    (int)(llx-AXIS_OOFFSET), (int)ypos);
	        fprintf (fp, "    (%g) %d %d axlabel\n", 
		    yval, 
		    (int)(llx-(yval>=1000?27:(yval>=100?20:16))), 
		    (int)ypos-2); 
	        Mval += Mtic;
	    } else
	        fprintf (fp, "\t%4d %4d yMinorTicmark\n", 
		    (int)(llx-AXIS_OOFFSET), (int)ypos);
	    yval += mtic;
	    ypos += ystep;
	}
        fprintf (fp, "} def\n");
        fprintf (fp, "axLabelY\n");
}


/* EPS_LANDSCAPELABELS -- Write out the labeling procedures for a landscape
** mode image.
*/
static void 
eps_landLabels (fp, psim, scols, srows, icols, irows, llx, lly)
FILE	*fp;
PSImagePtr psim;
int	scols, srows;
int	icols, irows;
float	llx, lly;
{
	float	xpos, xstep, ypos, ystep;
	int	start, end, range;
        float   Mval, xval=0.0, yval=0.0, tic, mtic, Mtic;


	/* X Axis labeling and ticmarks. */
        fprintf (fp, "/axLabelX {\n");
        if (psim->ury > psim->lly) {
            start = psim->lly;
            end = psim->ury;
        } else {
            start = psim->ury;
            end = psim->lly;
        }  
	range = end - start + 1;
	Mtic = tic = ticstep ((float)range, (range>=256 ? NTICMARKS : 3));
	mtic = (float) tic / (tic < 100 ? 5. : 10.);
        Mval = ( (int)(start + Mtic) / (int) Mtic) * Mtic;
        xval = ( (int)(start + mtic) / (int) mtic) * mtic;
        xstep = mtic * ((float)scols/(float)(range));
        if (psim->ury > psim->lly)
            xpos = (llx + scols) - ((float)(xval-start) / (float)range * scols);
        else {
            xpos = llx + ((float)(xval-start) / (float)range * scols);
            xstep = -xstep;
        }
	while (xval <= end ) {
	    if ( xval == Mval ) {
	        fprintf (fp, "    %4d %4d xMajorTicmark\t", 
		    (int)xpos, (int)(lly-AXIS_OOFFSET));
	        fprintf (fp, "    (%g) %d %d axlabel\n", 
		    xval,
		    (int)xpos+2,
		    (int)(lly-(yval>=1000?30:(yval>=100?25:20))) );
	        Mval += Mtic;
	    } else
	        fprintf (fp, "\t%4d %4d xMinorTicmark\n", 
		    (int)xpos, (int)(lly-AXIS_OOFFSET));
	    xval += mtic;
	    xpos -= xstep;
	}
        fprintf (fp, "} def\n");
        fprintf (fp, "axLabelX\n");

	/* Y Axis labeling and ticmarks. */
        fprintf (fp, "/axLabelY {\n");
        if (psim->urx > psim->llx) {
            start = psim->llx;
            end = psim->urx;
        } else {
            start = psim->urx;
            end = psim->llx;
        }  
	Mtic = tic = ticstep ((float)range, (range>=256 ? NTICMARKS : 3));
	mtic = (float) tic / (tic < 100 ? 5. : 10.);
        Mval = ( (int)(start + Mtic) / (int) Mtic) * Mtic;
        yval = ( (int)(start + mtic) / (int) mtic) * mtic;
        ystep = mtic * ((float)scols/(float)(range));
        if (psim->urx > psim->llx)
            ypos = lly + ( (float)(yval - start) / (float)range * scols);
        else {
            ypos = (lly + srows) - ((float)(yval-start) / (float)range * scols);
            ystep = -ystep;
        }
        while (yval <= end) {  
	    if ( yval == Mval ) {
	        fprintf (fp, "    %4d %4d yMajorTicmark\t", 
		    (int)(llx-AXIS_OOFFSET), (int)ypos);
	        fprintf (fp, "    (%g) %d %d axlabel\n", 
		    yval, 
		    (int)(llx+scols+(2*AXIS_OOFFSET)+2),
		    (int)ypos-(yval>=1000?9:(yval>=100?6:2)) ); 
	        Mval += Mtic;
	    } else
	        fprintf (fp, "\t%4d %4d yMinorTicmark\n", 
		    (int)(llx-AXIS_OOFFSET), (int)ypos);
	    yval += mtic;
	    ypos += ystep;
	}
        fprintf (fp, "} def\n");
        fprintf (fp, "axLabelY\n");
}


/* EPS_DOCOLORBAR --  Annotate the image with a colorbar.
*/

static void 
eps_doColorbar (fp, psim, scols, srows, llx, lly, turnflag)
FILE	*fp;
PSImagePtr psim;
int	scols, srows;
float	llx, lly;
int	turnflag;
{
	register int i, j, cbar_size;
        int     ncolors, nlabels, pos, step, cmel, cmstep, val;


	/* Colorbar label font definitions. */
	fprintf (fp, "/cblabelfont /Times-Roman findfont 10 scalefont def\n");
	fprintf (fp, "/cblabel { moveto cblabelfont setfont %s show %s } def\n",
	    (turnflag ? "90 rotate" : " "),
	    (turnflag ? "-90 rotate" : " "));

	/* A border for the colorbar. */
	fprintf (fp, "/cbarBorder {\n");
	if (turnflag) {
	    cbar_size = MIN (512, MAX (256, srows + 2)) - 1;
	    fprintf (fp, "   %4d %4d moveto\n", 
		(int)llx + scols + 31, 
		(int)lly + (srows/2) - (cbar_size/2) - 1);
	    fprintf (fp, "   17      0 rlineto\n");
	    fprintf (fp, "   0    %4d rlineto\n",  cbar_size + 3);
	    fprintf (fp, "   -17     0 rlineto\n");
	} else {
	    cbar_size = MIN (512, MAX (256, scols + 2));
	    fprintf (fp, "   %-4d %4d moveto\n", 
		(int)llx + (scols/2) - (cbar_size/2) - 1, 
		(int)(lly - 46));
	    fprintf (fp, "   0      14 rlineto\n");
	    fprintf (fp, "   %-4d    0 rlineto\n", cbar_size + 3);
	    fprintf (fp, "   0     -14 rlineto\n");
	}
	fprintf (fp, "   closepath\n");
	fprintf (fp, "   1 setlinewidth\n");
	fprintf (fp, "   stroke\n");
	fprintf (fp, "} def\n");
	fprintf (fp, "cbarBorder\n");

	/* Draw the colorbar labels, but only for grayscale images. */
	ncolors = psim->cmap.max - psim->cmap.min + 1;
	nlabels = 5;
	if (turnflag)
	    pos = (int)lly + (srows/2) - (cbar_size/2);
	else
	    pos = (int)llx + (scols/2) - (cbar_size/2);
	step = cbar_size / nlabels;
	cmel = psim->cmap.min;
	cmstep = ncolors / nlabels;
	for (i=0; i <= nlabels; i++) {
	    val = MONO(psim->cmap.r[cmel],	    /* get grayscale value */
		       psim->cmap.g[cmel],
		       psim->cmap.b[cmel]);
	     if (psim->z1 != 0.0 && psim->z2 != 0.0) {
		/* We have a transformation defined, convert the grayscale
		 * value to original image values.   Assumes a linear
		 * transformation, for a log transformation the wcsbox
	 	 * reports only screen units so we'll do that here as well.
		 */
		if (psim->ztype == EPS_LINEAR)
		    val = ((psim->z2-psim->z1)/(float)ncolors)*cmel + psim->z1;
	    }

	    if (turnflag) 
	        fprintf (fp, "(%d) %d %d cblabel\n", 
		    val, 
		    (int)llx + scols + 57, 
		    pos-(val<100?3:6));
	    else
	        fprintf (fp, "(%d) %d %d cblabel\n", 
		    val, 
		    pos-(val<100?3:6), 
		    (int)(lly-55));
	    cmel += cmstep;
	    cmel = (cmel < psim->cmap.max ? cmel : psim->cmap.max);
	    pos += step;
	}

	/* Draw the colorbar. */
	if (psim->colorClass == EPS_GRAYSCALE) {
            fprintf (fp, "/cbarstr %d string def\n", ncolors);
            fprintf (fp, "gsave\n" );
	    if (turnflag) {
                fprintf (fp, "%d %d translate\n",
		    (int)(llx + scols + 45), 
		    (int)(lly + (srows/2) - (cbar_size/2)) + 1);
	        fprintf (fp, 
		    "0.5 0.5 translate  90 rotate  -0.5 -0.5 translate\n");
	    } else {
                fprintf (fp, "%g %g translate\n", 
		    llx + (scols/2) - (cbar_size/2) + 1, 
		    lly - 45 );
	    }
            fprintf (fp, "%d 12 scale\n", cbar_size);
            fprintf (fp, "%d 1 8  [ %d 0 0 1 0 0 ]\n", ncolors, ncolors);

            fprintf (fp, "{ cbarstr readstring }\n" );
            fprintf (fp, "image\n" );

	} else {
            fprintf (fp, "DisplayImage\n" );
            if (turnflag) {
                fprintf (fp, "%d %d\n", 
                    (int)(llx + scols + 34),
                    (int)(lly + (srows/2) - (cbar_size/2)));
                fprintf (fp, "12 %d\n", cbar_size);
            } else {
                fprintf (fp, "%d %d\n",  
		    (int)llx + (scols/2) - (cbar_size/2), 
		    (int)lly - 45 );
                fprintf (fp, "%d 12\n", cbar_size);
	    }
            fprintf (fp, "%d 1\n", ncolors);
            fprintf (fp, "%d\n", turnflag);
            fprintf (fp, "0\n");
            fprintf (fp, "1\n");
	}

	/* Write out the colormap used. */
	if (psim->colorClass == EPS_GRAYSCALE) {
	    for (i=psim->cmap.min; i <= psim->cmap.max; i++ ) {
	        fprintf (fp, "%02x", 
	            MONO(psim->cmap.r[i],psim->cmap.g[i], psim->cmap.b[i]));
	        if ((i+1) % 32 == 0)
		    fprintf (fp, "\n");
	    }
     	    fprintf (fp, "\n");
            fprintf (fp, "grestore\n");
	} else {
	    for (j=1, i=psim->cmap.min; i <= psim->cmap.max; i++, j++ )
	        fprintf (fp, "%02x%02x%02x\n", 
		    psim->cmap.r[i],psim->cmap.g[i], psim->cmap.b[i]);
		if (j % 12 ==0)
		    fprintf (fp, "\n");
	}
}


/* EPS_COLORHEADER - Write the pseudocolor header prolog and compute EPS page
** parameters. 
*/
static char *EPSColorProlog[]=
    {
      "%%BeginProlog",
      "%",
      "% Display a color image.  The image is displayed in color on",
      "% Postscript viewers or printers that support color, otherwise",
      "% it is displayed as grayscale.",
      "%",
      "/buffer 512 string def",
      "/byte 1 string def",
      "/color_packet 3 string def",
      "/pixels 768 string def",
      "",
      "/DirectClassPacket",
      "{",
      "  %",
      "  % Get a DirectClass packet.",
      "  %",
      "  % Parameters: ",
      "  %   red.",
      "  %   green.",
      "  %   blue.",
      "  %   length: number of pixels minus one of this color (optional).",
      "  %",
      "  currentfile color_packet readhexstring pop pop",
      "  compression 0 gt",
      "  {",
      "    /number_pixels 3 def",
      "  }",
      "  {",
      "    currentfile byte readhexstring pop 0 get",
      "    /number_pixels exch 1 add 3 mul def",
      "  } ifelse",
      "  0 3 number_pixels 1 sub",
      "  {",
      "    pixels exch color_packet putinterval",
      "  } for",
      "  pixels 0 number_pixels getinterval",
      "} bind def",
      "",
      "/DirectClassImage",
      "{",
      "  %",
      "  % Display a DirectClass image.",
      "  %",
      "  systemdict /colorimage known",
      "  {",
      "    columns rows 8",
      "    [",
      "      columns 0 0",
      "      rows neg 0 rows",
      "    ]",
      "    { DirectClassPacket } false 3 colorimage",
      "  }",
      "  {",
      "    %",
      "    % No colorimage operator;  convert to grayscale.",
      "    %",
      "    columns rows 8",
      "    [",
      "      columns 0 0",
      "      rows neg 0 rows",
      "    ]",
      "    { GrayDirectClassPacket } image",
      "  } ifelse",
      "} bind def",
      "",
      "/GrayDirectClassPacket",
      "{",
      "  %",
      "  % Get a DirectClass packet;  convert to grayscale.",
      "  %",
      "  % Parameters: ",
      "  %   red",
      "  %   green",
      "  %   blue",
      "  %   length: number of pixels minus one of this color (optional).",
      "  %",
      "  currentfile color_packet readhexstring pop pop",
      "  color_packet 0 get 0.299 mul",
      "  color_packet 1 get 0.587 mul add",
      "  color_packet 2 get 0.114 mul add",
      "  cvi",
      "  /gray_packet exch def",
      "  compression 0 gt",
      "  {",
      "    /number_pixels 1 def",
      "  }",
      "  {",
      "    currentfile byte readhexstring pop 0 get",
      "    /number_pixels exch 1 add def",
      "  } ifelse",
      "  0 1 number_pixels 1 sub",
      "  {",
      "    pixels exch gray_packet put",
      "  } for",
      "  pixels 0 number_pixels getinterval",
      "} bind def",
      "",
      "/GrayPseudoClassPacket",
      "{",
      "  %",
      "  % Get a PseudoClass packet;  convert to grayscale.",
      "  %",
      "  % Parameters: ",
      "  %   index: index into the colormap.",
      "  %   length: number of pixels minus one of this color (optional).",
      "  %",
      "  currentfile byte readhexstring pop 0 get",
      "  /offset exch 3 mul def",
      "  /color_packet colormap offset 3 getinterval def",
      "  color_packet 0 get 0.299 mul",
      "  color_packet 1 get 0.587 mul add",
      "  color_packet 2 get 0.114 mul add",
      "  cvi",
      "  /gray_packet exch def",
      "  compression 0 gt",
      "  {",
      "    /number_pixels 1 def",
      "  }",
      "  {",
      "    currentfile byte readhexstring pop 0 get",
      "    /number_pixels exch 1 add def",
      "  } ifelse",
      "  0 1 number_pixels 1 sub",
      "  {",
      "    pixels exch gray_packet put",
      "  } for",
      "  pixels 0 number_pixels getinterval",
      "} bind def",
      "",
      "/PseudoClassPacket",
      "{",
      "  %",
      "  % Get a PseudoClass packet.",
      "  %",
      "  % Parameters: ",
      "  %   index: index into the colormap.",
      "  %   length: number of pixels minus one of this color (optional).",
      "  %",
      "  currentfile byte readhexstring pop 0 get",
      "  /offset exch 3 mul def",
      "  /color_packet colormap offset 3 getinterval def",
      "  compression 0 gt",
      "  {",
      "    /number_pixels 3 def",
      "  }",
      "  {",
      "    currentfile byte readhexstring pop 0 get",
      "    /number_pixels exch 1 add 3 mul def",
      "  } ifelse",
      "  0 3 number_pixels 1 sub",
      "  {",
      "    pixels exch color_packet putinterval",
      "  } for",
      "  pixels 0 number_pixels getinterval",
      "} bind def",
      "",
      "/PseudoClassImage",
      "{",
      "  %",
      "  % Display a PseudoClass image.",
      "  %",
      "  % Parameters: ",
      "  %   colors: number of colors in the colormap.",
      "  %   colormap: red, green, blue color packets.",
      "  %",
      "  currentfile buffer readline pop",
      "  token pop /colors exch def pop",
      "  /colors colors 3 mul def",
      "  /colormap colors string def",
      "  currentfile colormap readhexstring pop pop",
      "  systemdict /colorimage known",
      "  {",
      "    columns rows 8",
      "    [",
      "      columns 0 0",
      "      rows neg 0 rows",
      "    ]",
      "    { PseudoClassPacket } false 3 colorimage",
      "  }",
      "  {",
      "    %",
      "    % No colorimage operator;  convert to grayscale.",
      "    %",
      "    columns rows 8",
      "    [",
      "      columns 0 0",
      "      rows neg 0 rows",
      "    ]",
      "    { GrayPseudoClassPacket } image",
      "  } ifelse",
      "} bind def",
      "",
      "/DisplayImage",
      "{",
      "  %",
      "  % Display a DirectClass or PseudoClass image.",
      "  %",
      "  % Parameters: ",
      "  %   x & y translation.",
      "  %   x & y scale.",
      "  %   image columns & rows.",
      "  %   orientation: 0-Portrait or 1-Landscape",
      "  %   class: 0-DirectClass or 1-PseudoClass.",
      "  %   compression: 0-RunlengthEncodedCompression or 1-NoCompression.",
      "  %   hex color packets.",
      "  %",
      "  gsave",
      "  currentfile buffer readline pop",
      "  token pop /x exch def",
      "  token pop /y exch def pop",
      "  x y translate",
      "  currentfile buffer readline pop",
      "  token pop /x exch def",
      "  token pop /y exch def pop",
      "  x y scale",
      "  currentfile buffer readline pop",
      "  token pop /columns exch def",
      "  token pop /rows exch def pop",
      "  currentfile buffer readline pop",
      "  token pop /orient exch def pop",
      "  orient 0 gt { 0.5 0.5 translate  90 rotate  -0.5 -0.5 translate } if",
      "  currentfile buffer readline pop",
      "  token pop /class exch def pop",
      "  currentfile buffer readline pop",
      "  token pop /compression exch def pop",
      "  class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
      "  grestore",
      "} bind def",
      "%%EndProlog",
      "%%Page:  1 1",
      NULL
};


static void
eps_colorHeader (psim, fp)
PSImagePtr psim;
FILE	   *fp;
{
	register char **line;
	int icols=0, irows=0, scols=0, srows=0, turnflag=0;
	float   llx = 0.0, lly = 0.0;
 	time_t  timer;


	/* Get the common page parameters. */
	eps_pageParams (psim, &llx, &lly, &icols, &irows, &scols, &srows,
	    &turnflag);

	/* Now write header and prolog stuff */
	fprintf (fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
	fprintf (fp, "%%%%Title: XImtool Screen Hardcopy\n");
	fprintf (fp, "%%%%Creator: XImtool\n");
  	timer = time ((time_t *) NULL);
	(void) localtime (&timer);
	fprintf (fp, "%%%%CreationDate: %s", ctime(&timer));
	if (psim->annotate) 
	    fprintf (fp, "%%%%BoundingBox: %d %d %d %d\n",
                (int) (MAX (0, llx - X_ANNOT_MARGIN)), 
	        (int) (MAX (0, lly - Y_ANNOT_MARGIN)),
                (int) ( llx + scols + 0.5 + X_ANNOT_MARGIN), 
	        (int) ( lly + srows + 0.5 + Y_ANNOT_MARGIN) );
	else
	    fprintf (fp, "%%%%BoundingBox: %d %d %d %d\n",
                (int) (MAX (0, llx - 10)), 
	        (int) (MAX (0, lly - 10)),
                (int) ( llx + scols + 0.5 + 10), 
	        (int) ( lly + srows + 0.5 + 10) );
	fprintf (fp, "%%%%Pages: 1\n");
	fprintf (fp, "%%%%EndComments\n");

  	/* Output remaining Postscript prolog commands.  */
  	for (line = EPSColorProlog; *line; line++)
    	    fprintf (fp, "%s\n",*line);
    	fprintf (fp, "userdict begin\n");
  	fprintf (fp, "%%%%BeginData:\n");

	fprintf (fp, "DisplayImage\n");

	/* Now write the image display parameters, specifically
	 *
	 *   x & y translation.
	 *   x & y scale.
	 *   image columns & rows.
	 *   orientation: 0-Portrait or 1-Landscape
	 *   class: 0-DirectClass or 1-PseudoClass.
	 *   compression: 0-RunlengthEncodedCompression or 1-NoCompression.
	 *   hex color packets.
	 */

 	fprintf (fp, "%d %d\n%u %u\n%u %u\n%d\n%d\n%d\n",
            (int) llx, (int) lly,
	    (int) scols, (int) srows,
	    psim->cols, psim->rows,
	    turnflag,
            psim->colorClass == EPS_PSEUDOCOLOR,
	    psim->compression == NoCompression);
}


/* EPS_WRITETRAILER -- Output Postscript trailer blurb.
*/
static void
eps_writeTrailer (fp)
FILE	*fp;
{
	fprintf (fp, "\n");
	fprintf (fp, "showpage\n");
	fprintf (fp, "%%%%EndData\n");
	fprintf (fp, "end\n");
	fprintf (fp, "%%%%PageTrailer\n");
	fprintf (fp, "%%%%Trailer\n");
	fprintf (fp, "%%%%EOF\n");
}


/* EPS_SIMPLETRAILER -- Output Postscript trailer blurb.
*/
static void
eps_simpleTrailer (fp)
FILE	*fp;
{
	fprintf (fp, "showpage\n");
}


static void 
eps_flushPix (fp)
FILE	*fp;
{
	pixbuf[pixnum] = '\0';
	fprintf (fp, "%s", pixbuf);
	pixnum = 0;
	lpix = 0;
}


/* Utility Routines.
*/

/* TICSTEP --  calculate nice intervals for the ticmarks.
*/
static float
ticstep (range,nsteps)
float	range;
int	nsteps;
{
	double df, t2, t5, p1, p2, p3;
	float ticstep;
	int logtic;


        df = range / (float)(nsteps + 1);
        t2 = 0.301029996;
        t5 = 0.698970004;
        p1 = log10 ((double)(df > 0.0 ? df : -df));
        p2 = (int) p1;
        p3 = p1 - p2;
        if(p3 < 0.) {
            p3 = p2 + 1.;
            p2 = p2 - 1.;
	}

      if (p3 < 1.0e-10)
         ticstep = pow((double)10.0,(double)(p2));
      else if (p3 > 0. && p3 <= t2)
         ticstep = pow((double)10.0,(double)(p2+t2));
      else if (p3 > t2 && p3 <= t5)
         ticstep = pow((double)10.0,(double)(p2+t5));
      else if (p3 > t5 && p3 <= 1.) 
         ticstep = pow((double)10.0,(double)(p2+1.));
      else
         ticstep = df;

      logtic = (int) log10(ticstep) - 1;
      ticstep = (int)( (ticstep / pow((double)10.,(double)logtic)) *
	   pow((double)10.,(double)logtic) );

      if (ticstep < 0.1) ticstep = 0.10;

      return (ticstep);
}


/* MAKE_LABEL -- Generate the label for the output printer page.
*/
static char *
make_label()
{
        static  char buf[128];
        char    hostname[32];
        char    username[32];
        struct  passwd *pw;
        long    clock;


	bzero (buf, 128);
	bzero (hostname, 32);
	bzero (username, 32);

#ifdef SOLARIS
        sysinfo (SI_HOSTNAME, hostname, 32);
#else
        gethostname (hostname, 32);
#endif

        clock = time(0);
        pw = getpwuid (getuid());
        strcpy (username, pw->pw_name);
        endpwent();

        sprintf (buf, "NOAO/IRAF  %s@%s  %s",
            username, hostname, asctime(localtime(&clock)));

        return (buf);
}
