[comp.lang.postscript] gif2ps

dcj@bar.zk3.dec.com (Dave Jedlinsky OSEM) (03/23/90)

# Eat this, line-eater!

Enclosed is the source to gif2ps, which converts GIF files to
PostScript.  It is based on xgif, by John Bradley.  The current
implementation has a few nice features, and there's always room for
improvement.  The generated PostScript will work on all printers if the
original GIF file is grayscale, but a color picture requires that the
printer support the colorimage operator.

-David Jedlinsky
Digital Equipment Corporation   | 
dcj@decvax.dec.com              | This space intentionally left blank.
...!decwrl!decvax!dcj           | 

-----------------------------Cut Here-------------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./AUTHOR`
then
echo "writing ./AUTHOR"
cat > ./AUTHOR << '\End\Of\Shar\'
gif2ps converted by David C. Jedlinsky (dcj@decvax.dec.com), based on
the program xgif, by John Bradley.

-dcj

---
Written by John Bradley (bradley@cis.upenn.edu), one of the fine folks at 
the University of Pennsylvania.

Do whatever you want with this program, though it *would* be nice if my name
remained on it somewhere...  Other than that, it may be freely modified,
distributed, and used to fill up disk space.

--jhb
\End\Of\Shar\
else
  echo "will not over write ./AUTHOR"
fi
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\End\Of\Shar\'
#
# Makefile for gif2ps
#

OBJS = \
	psgif.o \
	psgifload.o

SRCS = \
	psgif.c \
	psgifload.c

.c.o:
	cc -c $*.c

gif2ps: ${OBJS}
	cc -o gif2ps ${OBJS}

psgifload.o: psgifload.c psgif.h

psgif.o: psgif.c psgif.h

clean:
	rm -rf *.o *~ gif2ps
\End\Of\Shar\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\End\Of\Shar\'
gif2ps is a program that converts GIF images to a form that can be
printed on an Postscript printer.  The images can be freely rescaled.

Based (heavily) on xgif, by John Bradley.

-David Jedlinsky (dcj@decvax.dec.com)

---
A collection of GIF images is available via anonymous ftp to 
"dsl.cis.upenn.edu" [128.91.2.12].

John Bradley  -  bradley@cis.upenn.edu
---

Revision History:

Removed X code, added PostScript output (dcj, 3/20/90).

Original version, converted from xgif, patchlevel 2 (2/13/89).
\End\Of\Shar\
else
  echo "will not over write ./README"
fi
if `test ! -s ./gif2ps.1`
then
echo "writing ./gif2ps.1"
cat > ./gif2ps.1 << '\End\Of\Shar\'
.TH gif2ps 1
.SH NAME
gif2ps \- converts GIF (*) pictures to PostScript (**)
.SH SYNTAX
\fBgif2ps\fP [-c] [-i] \fIfilename\fP [-l] [-o \fIfilename\fP] [-s
\fIscale\fP]
.SH DESCRIPTION
\fBgif2ps\fP is a conversion program which converts GIF images to the
PostScript language.
.SH OPTIONS
The '-c' option changes the output to a more space-efficient compact
representation.  The drawback of this option is that the computation
time on the side of the printer is increased by approximately a factor
of five.  It is most useful on a printer with a fast processor and a
slow serial interface, as it reduces the time to actually download the
picture.
.PP
The '-i' option specifies the input filename.  The '-i' itself is
optional, and is provided only for symmetry with the '-o' option.
.PP
The '-l' option renders the image in landscape mode (the image is
rotated 90 degrees from the orientation specified in the GIF file).
.PP
The '-o' option specifies the output filename.  If \fIfilename\fP is
not supplied, the PostScript code will be written to stdout.
.PP
The '-s' option specifies a scale factor, which must be greater than
zero.  \fIScale\fP can be a floating point number, the value defaults
to 1.
.PP
If the GIF image consists solely of grayscale colors, the generated
PostScript output will use the more efficient \fIimage\fP operator to
render the image.
.SH LIMITATIONS
Standard input is not a valid input file in the current
implementation.
.PP
If the GIF image is not a grayscale image, the printer must support
the \fIcolorimage\fP operator.  The generated code will cause a
printer which does not support the operator to print an error message
and quit.
.PP
This program ignores 'local colormaps' in GIF files (see the GIF spec
for details).  It also only displays the first image in GIF files that
have multiple images in them.
.PP
.SH AUTHOR
David Jedlinsky (dcj@decvax.dec.com), based (heavily) on xgif, by John
Bradley (bradley@cis.upenn.edu), which is in turn based (heavily) on
gif2ras.c, by Patrick J. Naughton (naughton@wind.sun.com), a program
that converts GIF pictures to Sun Rasterfiles.
.PP
(*) GIF is a no doubt a trademark of CompuServe, so watch it!
.PP
(**) PostScript is a trademark of Adobe Systems Incorporated.\End\Of\Shar\
else
  echo "will not over write ./gif2ps.1"
fi
if `test ! -s ./psgif.c`
then
echo "writing ./psgif.c"
cat > ./psgif.c << '\End\Of\Shar\'
/*
 * gif2ps.c - converts GIF pictures to Postscript.
 *
 *  Author:	David Jedlinsky, Digital Equipment Corporation
 *  		(dcj@decvax.dec.com)
 *  		John Bradley, University of Pennsylvania
 *  		(bradley@cis.upenn.edu)
 */

#define MAIN
#include "psgif.h"


/*******************************************/
main(argc, argv)
    int   argc;
    char *argv[];
/*******************************************/
{
    int        	i;
    char	*in, *out;
    FILE      	*outp;
    
    cmd = argv[0];
    in = out = NULL;
    compact = 0; landscape = 0; scale = 1.0;
    
    /*********************Options*********************/

    for (i = 1; i < argc; i++) {

      if (!strncmp(argv[i], "-c", 2)) {		/* compact */
	compact = 1;
	continue;
      }
      
      if (!strncmp(argv[i], "-l", 2)) {		/* landscape */
	landscape = 1;
	continue;
      }

      if (!strncmp(argv[i], "-s", 2)) {		/* scale */
	if (++i >= argc)
	  Syntax(cmd);
	if ((scale = atof(argv[i])) == 0.0) {
	  fprintf(stderr, "%s: Invalid scale.\n", cmd);
	  exit(1);
	}
	continue;
      }
	
      if (!strncmp(argv[i], "-i", 2)) {		/* input */
	if (++i >= argc)
	  Syntax(cmd);
	in = argv[i];
	continue;
      }
	
      if (!strncmp(argv[i], "-o", 2)) {		/* output */
	if (++i >= argc)
	  Syntax(cmd);
	out = argv[i];
	continue;
      }
      
      if (argv[i][0] != '-') {		/* the file name */
	in = argv[i];
	continue;
      }

      Syntax(cmd);
    }

    if (in == NULL) {
      /* in="-"; */
      Syntax(cmd);
    }

    /********** Open File/Write out Header Information********/

    if (out==NULL) {
      out = "stdout";
      outp=stdout;
    } else {
      outp=fopen(out, "w");
    }

    fprintf(outp, "%%!PS-Adobe-1.0\n");
    fprintf(outp, "%%%%Title: %s\n", out);
    fprintf(outp, "%%%%Creator: %s\n", cmd);
    fprintf(outp, "%%%%Pages: (atend)\n");
    fprintf(outp, "%%%%EndComments\n\n");

    /* Add macros needed here. */
    fprintf(outp, "%% GIF macros\n\n");
    
    fprintf(outp, "%%%%EndProlog\n\n");
    

    /***************** Open/Read the File  *****************/
    LoadGIF(in, outp);


    /*************** Write/Close Output File ***************/

    
    fprintf(outp, "%%%%Trailer\n");
    fprintf(outp, "%%%%Pages: 1\n");
    if (outp != stdout)
      if (fclose(outp) == EOF)
	fprintf(stderr, "%s: error closing %s.\n", cmd, out);
  }


/***********************************/
Syntax(cmd)
     char *cmd;
{
    fprintf(stderr,
	    "Usage: %s [-c] [-i] infile [-l] [-s scale] [-o outfile]\n",cmd);
    exit(1);
}


/***********************************/
FatalError (identifier)
       char *identifier;
{
    fprintf(stderr, "%s: %s\n",cmd, identifier);
    exit(-1);
}
\End\Of\Shar\
else
  echo "will not over write ./psgif.c"
fi
if `test ! -s ./psgif.h`
then
echo "writing ./psgif.h"
cat > ./psgif.h << '\End\Of\Shar\'
/*
 *  psgif.h  -  header file for gif2ps, but you probably already knew as much
 */


#define REVDATE   "Rev: 10/26/89"

/* include files */
#include <stdio.h>
#include <math.h>
#include <ctype.h>

#ifndef MAIN
#define WHERE extern
#else
#define WHERE
#endif

typedef unsigned char byte;

void *malloc(), exit(), _exit(), free();

/* global vars */
WHERE int numcols,compact,bw,landscape;
WHERE unsigned long cols[256];
WHERE char *cmd;
WHERE double scale;

#ifndef False
#define False 0
#define True !False
#endif
\End\Of\Shar\
else
  echo "will not over write ./psgif.h"
fi
if `test ! -s ./psgifload.c`
then
echo "writing ./psgifload.c"
cat > ./psgifload.c << '\End\Of\Shar\'
/*
 * psgifload.c  -  based strongly on...
 *
 * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
 *
 * Copyright (c) 1988, 1989 by Patrick J. Naughton
 *
 * Author: Patrick J. Naughton
 * naughton@wind.sun.com
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * This file is provided AS IS with no warranties of any kind.  The author
 * shall have no liability with respect to the infringement of copyrights,
 * trade secrets or any patents by this file or any part thereof.  In no
 * event will the author be liable for any lost revenue or profits or
 * other special, indirect and consequential damages.
 *
 */

#include "psgif.h"

typedef int boolean;

#define NEXTBYTE (*ptr++)
#define IMAGESEP 0x2c
#define INTERLACEMASK 0x40
#define COLORMAPMASK 0x80

FILE *fp;

int BitOffset = 0,              /* Bit Offset of next code */
    XC = 0, YC = 0,             /* Output X and Y coords of current pixel */
    Pass = 0,                   /* Used by output routine if interlaced pic */
    OutCount = 0,               /* Decompressor output 'stack count' */
    RWidth, RHeight,            /* screen dimensions */
    Width, Height,              /* image dimensions */
    LeftOfs, TopOfs,            /* image offset */
    BitsPerPixel,               /* Bits per pixel, read from GIF header */
    BytesPerScanline,           /* bytes per scanline in output raster */
    ColorMapSize,               /* number of colors */
    Background,                 /* background color */
    CodeSize,                   /* Code size, read from GIF header */
    InitCodeSize,               /* Starting code size, used during Clear */
    Code,                       /* Value returned by ReadCode */
    MaxCode,                    /* limiting value for current code size */
    ClearCode,                  /* GIF clear code */
    EOFCode,                    /* GIF end-of-information code */
    CurCode, OldCode, InCode,   /* Decompressor variables */
    FirstFree,                  /* First free code, generated per GIF spec */
    FreeCode,                   /* Decompressor, next free slot in hash
table */
    BitMask,                    /* AND mask for data size */
    ReadMask;                   /* Code AND mask for current code size */

byte FinChar;                   /* Decompressor variable */

boolean Interlace, HasColormap;
boolean Verbose = False;

byte *Image;                    /* The result array */
byte *RawGIF;                   /* The heap array to hold it, raw */
byte *Raster;                   /* The raster data stream, unblocked */

    /* The hash table used by the decompressor */
int Prefix[4096];
int Suffix[4096];

    /* An output array used by the decompressor */
byte OutCode[1025];

    /* The color map, read from the GIF header */
byte Red[256], Green[256], Blue[256], used[256];
int  numused;

char *id = "GIF87a";



/*****************************/
LoadGIF(fname, outp)
     char *fname;
     FILE *outp;
/*****************************/
{
    int            filesize;
    register byte  ch, ch1;
    register byte *ptr, *ptr1;
    register int   i;

    /* stdin won't work with the current implementation! */
/*    if (strcmp(fname,"-") == 0) {
      fp = stdin;
      fname = "<stdin>";
    } else*/
      fp = fopen(fname,"r");

    if (!fp) FatalError("file not found");

    /* find the size of the file */
    if (fseek(fp, 0L, 2) != 0)
      FatalError("couldn't seek to end of file");
    filesize = ftell(fp);
    if (fseek(fp, 0L, 0) != 0)
      FatalError("couldn't seek to start of file");

    if (!(ptr = RawGIF = (byte *) malloc((size_t)filesize)))
        FatalError("not enough memory to read gif file");

    if (!(Raster = (byte *) malloc((size_t)filesize)))
        FatalError("not enough memory to read gif file");

    if (fread((void *)ptr, (size_t)filesize, 1, fp) != (size_t)1)
        FatalError("GIF data read failed");

    if (strncmp((char *)ptr, id, 6))
        FatalError("not a GIF file");

    ptr += 6;

/* Get variables from the GIF screen descriptor */

    ch = NEXTBYTE;
    RWidth = ch + 0x100 * NEXTBYTE;     /* screen dimensions... not used. */
    ch = NEXTBYTE;
    RHeight = ch + 0x100 * NEXTBYTE;

    if (Verbose)
        fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight);

    ch = NEXTBYTE;
    HasColormap = ((ch & COLORMAPMASK) ? True : False);

    BitsPerPixel = (ch & 7) + 1;
    numcols = ColorMapSize = 1 << BitsPerPixel;
    BitMask = ColorMapSize - 1;

    Background = NEXTBYTE;              /* background color... not used. */

    if (NEXTBYTE)               /* supposed to be NULL */
        FatalError("corrupt GIF file (bad screen descriptor)");


/* Read in global colormap. */

    if (HasColormap) {
        if (Verbose)
            fprintf(stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n",
                fname, Width,Height,BitsPerPixel, ColorMapSize);
        for (i = 0; i < ColorMapSize; i++) {
            Red[i] = NEXTBYTE;
            Green[i] = NEXTBYTE;
            Blue[i] = NEXTBYTE;
            used[i] = 0;
          }
        numused = 0;

        }

    else {  /* no colormap in GIF file */
        fprintf(stderr,"%s:  warning!  no colortable in this file. 
Winging it.\n",cmd);
        if (!numcols) numcols=256;
        for (i=0; i<numcols; i++) cols[i] = (unsigned long) i;
        }

/* Check for image seperator */

    if (NEXTBYTE != IMAGESEP)
        FatalError("corrupt GIF file (no image separator)");

/* Now read in values from the image descriptor */

    ch = NEXTBYTE;
    LeftOfs = ch + 0x100 * NEXTBYTE;
    ch = NEXTBYTE;
    TopOfs = ch + 0x100 * NEXTBYTE;
    ch = NEXTBYTE;
    Width = ch + 0x100 * NEXTBYTE;
    ch = NEXTBYTE;
    Height = ch + 0x100 * NEXTBYTE;
    Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);

    if (Verbose)
        fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
                Width, Height, (Interlace) ? "" : "non-");

    else 
        fprintf(stderr, "%s:  %s is %dx%d, %d colors  ",
           cmd, fname, Width,Height,ColorMapSize);
    

/* Note that I ignore the possible existence of a local color map.
 * I'm told there aren't many files around that use them, and the spec
 * says it's defined for future use.  This could lead to an error
 * reading some files. 
 */

/* Start reading the raster data. First we get the intial code size
 * and compute decompressor constant values, based on this code size.
 */

    CodeSize = NEXTBYTE;
    ClearCode = (1 << CodeSize);
    EOFCode = ClearCode + 1;
    FreeCode = FirstFree = ClearCode + 2;

/* The GIF spec has it that the code size is the code size used to
 * compute the above values is the code size given in the file, but the
 * code size used in compression/decompression is the code size given in
 * the file plus one. (thus the ++).
 */

    CodeSize++;
    InitCodeSize = CodeSize;
    MaxCode = (1 << CodeSize);
    ReadMask = MaxCode - 1;

/* Read the raster data.  Here we just transpose it from the GIF array
 * to the Raster array, turning it from a series of blocks into one long
 * data stream, which makes life much easier for ReadCode().
 */

    ptr1 = Raster;
    
    do {
        ch = ch1 = NEXTBYTE;
        while (ch--) *ptr1++ = NEXTBYTE;
        if ((ptr1 - Raster) > filesize) {
          FatalError("corrupt GIF file (unblock)");
        }         
    } while(ch1);

    free((void *)RawGIF);       /* We're done with the raw data now... */

    if (Verbose) {
        fprintf(stderr, "done.\n");
        fprintf(stderr, "Decompressing...");
    }

/* Allocate buffer to hold decompressed image */
    Image = (byte *)malloc((size_t)Width*Height);
    if (!Image) FatalError("not enough memory for Image");
    BytesPerScanline = Width;
    
/* Decompress the file, continuing until you see the GIF EOF code.
 * One obvious enhancement is to add checking for corrupt files here.
 */

    Code = ReadCode();
    while (Code != EOFCode) {

/* Clear code sets everything back to its initial value, then reads the
 * immediately subsequent code as uncompressed data.
 */

        if (Code == ClearCode) {
            CodeSize = InitCodeSize;
            MaxCode = (1 << CodeSize);
            ReadMask = MaxCode - 1;
            FreeCode = FirstFree;
            CurCode = OldCode = Code = ReadCode();
            FinChar = CurCode & BitMask;
            AddToPixel(FinChar);
        }
        else {

/* If not a clear code, then must be data: save same as CurCode and InCode */

            CurCode = InCode = Code;

/* If greater or equal to FreeCode, not in the hash table yet;
 * repeat the last character decoded
 */

            if (CurCode >= FreeCode) {
                CurCode = OldCode;
                OutCode[OutCount++] = FinChar;
            }

/* Unless this code is raw data, pursue the chain pointed to by CurCode
 * through the hash table to its end; each code in the chain puts its
 * associated output code on the output queue.
 */

            while (CurCode > BitMask) {
                if (OutCount > 1024) {
                    fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n");
                    _exit(-1);  /* calling 'exit(-1)' dumps core, so I don't */
                    }
                OutCode[OutCount++] = Suffix[CurCode];
                CurCode = Prefix[CurCode];
            }

/* The last code in the chain is treated as raw data. */

            FinChar = CurCode & BitMask;
            OutCode[OutCount++] = FinChar;

/* Now we put the data out to the Output routine.
 * It's been stacked LIFO, so deal with it that way...
 */

            for (i = OutCount - 1; i >= 0; i--)
                AddToPixel(OutCode[i]);
            OutCount = 0;

/* Build the hash table on-the-fly. No table is stored in the file. */

            Prefix[FreeCode] = OldCode;
            Suffix[FreeCode] = FinChar;
            OldCode = InCode;

/* Point to the next slot in the table.  If we exceed the current
 * MaxCode value, increment the code size unless it's already 12.  If it
 * is, do nothing: the next code decompressed better be CLEAR
 */

            FreeCode++;
            if (FreeCode >= MaxCode) {
                if (CodeSize < 12) {
                    CodeSize++;
                    MaxCode *= 2;
                    ReadMask = (1 << CodeSize) - 1;
                }
            }
        }
        Code = ReadCode();
    }

    free((void *)Raster);

    if (Verbose)
        fprintf(stderr, "done.\n");
    else
        fprintf(stderr,"(of which %d are used)\n",numused);

    if (fp != stdin)
        if (fclose(fp) == EOF)
	  fprintf(stderr, "%s: error closing %s.\n", cmd, fname);

    ColorDicking(fname);

    WriteGIFdata(outp);
}


/* Fetch the next code from the raster data stream.  The codes can be
 * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
 * maintain our location in the Raster array as a BIT Offset.  We compute
 * the byte Offset into the raster array by dividing this by 8, pick up
 * three bytes, compute the bit Offset into our 24-bit chunk, shift to
 * bring the desired code to the bottom, then mask it off and return it. 
 */
ReadCode()
{
int RawCode, ByteOffset;

    ByteOffset = BitOffset / 8;
    RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
    if (CodeSize >= 8)
        RawCode += (0x10000 * Raster[ByteOffset + 2]);
    RawCode >>= (BitOffset % 8);
    BitOffset += CodeSize;
    return(RawCode & ReadMask);
}


AddToPixel(Index)
byte Index;
{
  if (YC<Height)
        *(Image + YC * BytesPerScanline + XC) = Index;

    if (!used[Index]) { used[Index]=1;  numused++; }

/* Update the X-coordinate, and if it overflows, update the Y-coordinate */

    if (++XC == Width) {

/* If a non-interlaced picture, just increment YC to the next scan line. 
 * If it's interlaced, deal with the interlace as described in the GIF
 * spec.
 */

        XC = 0;
        if (!Interlace) YC++;
        else {
            switch (Pass) {
                case 0:
                    YC += 8;
                    if (YC >= Height) {
                        Pass++;
                        YC = 4;
                    }
                break;
                case 1:
                    YC += 8;
                    if (YC >= Height) {
                        Pass++;
                        YC = 2;
                    }
                break;
                case 2:
                    YC += 4;
                    if (YC >= Height) {
                        Pass++;
                        YC = 1;
                    }
                break;
                case 3:
                    YC += 2;
                break;
                default:
                break;
            }
        }
    }
}



/*************************/
ColorDicking(fname)
char *fname;
{
  int i;

  bw = 1;
  
  for (i = 0; i < ColorMapSize; i++)
    if (used[i] && ((Red[i] != Green[i]) || (Red[i] != Blue[i]) ||
                    (Green[i] != Blue[i])))
      bw = 0;

  if (bw)
    fprintf(stderr, "%s: %s is a grayscale image.\n", cmd, fname);
}


/*************************/
WriteGIFdata(fp)
     FILE *fp;
{
  int i, j, count = 1;
  double sx, sy, tx, ty, tmp;
  byte *ptr = Image;

  fprintf(fp, "%%%%Page: 1 1\n\n");

  sx = (double)Width * scale;
  sy = (double)Height * scale;
  
  if (landscape) {
    tx = 306.0 + sy / 2;
    ty = 396.0 - sx / 2;
    tmp = sx;
    sx = sy;
    sy = tmp;
  } else {
    tx = 306.0 - sx / 2;
    ty = 396.0 - sy / 2;
  }
  
  if (!bw) {
    fprintf(fp, "systemdict /colorimage known\n");
    fprintf(fp, "userdict /colorimage known\n");
    fprintf(fp, "or not\n");
    fprintf(fp, "{\n");
    fprintf(fp, "  /Times-Roman findfont 20 scalefont setfont\n");
    fprintf(fp, "  72 72 moveto\n");
    fprintf(fp, "  (This picture requires the colorimage operator.) show\n");
    fprintf(fp, "  showpage stop\n");
    fprintf(fp, "} if\n\n");

    if (compact) {
      fprintf(fp, "/ColorMap %d array def\n", ColorMapSize);
    
      for (i=0; i<ColorMapSize; i++) {
	if (i % 8 == 0)
	  fprintf(fp, "\n");
	fprintf(fp, "<%02x%02x%02x> ", Red[i], Green[i], Blue[i]);
      }
      fprintf(fp, "\nColorMap astore\n\n");
    
      fprintf(fp, "/rgbstr 3 string def\n");
      fprintf(fp, "/nextch 1 string def\n");
      /* Center the image on a 8.5x11 sheet of paper */
      fprintf(fp, "%.1f %.1f translate\n", tx, ty);
      fprintf(fp, "%.1f %.1f scale\n", sx, sy);
      if (landscape)
	fprintf(fp, "90 rotate\n");
      fprintf(fp, "%d %d 8\n", Width, Height);
      fprintf(fp, "[%d 0 0 %d 0 %d]\n", Width, -Height, Height);
      fprintf(fp, "{\n");
      fprintf(fp, "  currentfile nextch readhexstring\n");
      fprintf(fp, "  {\n");
      fprintf(fp, "    0 get\n");
      fprintf(fp, "    ColorMap exch get\n");
      fprintf(fp, "  } {\n");
      fprintf(fp, "    ()\n");
      fprintf(fp, "  } ifelse\n");
      fprintf(fp, "} bind false 3 colorimage\n\n");
    
      ptr = Image;
      for (i=0; i<Height; i++)
	for (j=0; j<Width; j++,ptr++) {
	  fprintf(fp, "%02x", *ptr);
	  if (count++ > 31) {
	    count = 1;
	    fprintf(fp, "\n");
	  }
	}
    } else {
      fprintf(fp, "/rgbstr 256 string def\n");
      fprintf(fp, "%.1f %.1f translate\n", tx, ty);
      fprintf(fp, "%.1f %.1f scale\n", sx, sy);
      if (landscape)
	fprintf(fp, "90 rotate\n");
      fprintf(fp, "%d %d 8\n", Width, Height);
      fprintf(fp, "[%d 0 0 %d 0 %d]\n", Width, -Height, Height);
      fprintf(fp, "{ currentfile rgbstr readhexstring pop }\n");
      fprintf(fp, "bind false 3 colorimage\n\n");
    
      ptr = Image;
      for (i=0; i<Height; i++)
	for (j=0; j<Width; j++,ptr++) {
	  fprintf(fp, "%02x%02x%02x", Red[*ptr], Green[*ptr], Blue[*ptr]);
	  if (count++ > 7) {
	    count = 1;
	    fprintf(fp, "\n");
	  }
	}
    }
  } else { /* B&W */
    fprintf(fp, "/picstr 256 string def\n");
    fprintf(fp, "%.1f %.1f translate\n", tx, ty);
    fprintf(fp, "%.1f %.1f scale\n", sx, sy);
    if (landscape)
      fprintf(fp, "90 rotate\n");
    fprintf(fp, "%d %d 8\n", Width, Height);
    fprintf(fp, "[%d 0 0 %d 0 %d]\n", Width, -Height, Height);
    fprintf(fp, "{ currentfile picstr readhexstring pop }\n");
    fprintf(fp, "bind image\n\n");

    ptr = Image;
    for (i=0; i<Height; i++)
      for (j=0; j<Width; j++,ptr++) {
	fprintf(fp, "%02x", Red[*ptr]);
	if (count++ > 31) {
	  count = 1;
	  fprintf(fp, "\n");
	}
      }
  }
    
  fprintf(fp, "\n\nshowpage\n");
}
\End\Of\Shar\
else
  echo "will not over write ./psgifload.c"
fi
echo "Finished archive 1 of 1"
exit

dcj@bar.zk3.dec.com (Dave Jedlinsky OSEM) (03/27/90)

# Eat this, line-eater!

Whoops, the shar file I posted was corrupt.  That'll teach me to post
something without testing to make sure it unarchives correctly.  Here is
a working version of the gif2ps source code.

-David Jedlinsky
Digital Equipment Corporation   | Hey, I just work here.  They don't
dcj@decvax.dec.com              | have anything to do with these opinions.
...!decwrl!decvax!dcj           |

-----------------------------Cut Here---------------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./AUTHOR`
then
echo "writing ./AUTHOR"
cat > ./AUTHOR << '\End\Of\Shar\'
gif2ps converted by David C. Jedlinsky (dcj@decvax.dec.com), based on
the program xgif, by John Bradley.

-dcj

---
Written by John Bradley (bradley@cis.upenn.edu), one of the fine folks at 
the University of Pennsylvania.

Do whatever you want with this program, though it *would* be nice if my name
remained on it somewhere...  Other than that, it may be freely modified,
distributed, and used to fill up disk space.

--jhb
\End\Of\Shar\
else
  echo "will not over write ./AUTHOR"
fi
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\End\Of\Shar\'
#
# Makefile for gif2ps
#

OBJS = \
	psgif.o \
	psgifload.o

SRCS = \
	psgif.c \
	psgifload.c

.c.o:
	cc -c $*.c

gif2ps: ${OBJS}
	cc -o gif2ps ${OBJS}

psgifload.o: psgifload.c psgif.h

psgif.o: psgif.c psgif.h

clean:
	rm -rf *.o *~ gif2ps
\End\Of\Shar\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\End\Of\Shar\'
gif2ps is a program that converts GIF images to a form that can be
printed on an Postscript printer.  The images can be freely rescaled.

Based (heavily) on xgif, by John Bradley.

-David Jedlinsky (dcj@decvax.dec.com)

---
A collection of GIF images is available via anonymous ftp to 
"dsl.cis.upenn.edu" [128.91.2.12].

John Bradley  -  bradley@cis.upenn.edu
---

Revision History:

Removed X code, added PostScript output (dcj, 3/20/90).

Original version, converted from xgif, patchlevel 2 (2/13/89).
\End\Of\Shar\
else
  echo "will not over write ./README"
fi
if `test ! -s ./gif2ps.1`
then
echo "writing ./gif2ps.1"
cat > ./gif2ps.1 << '\End\Of\Shar\'
.TH gif2ps 1
.SH NAME
gif2ps \- converts GIF (*) pictures to PostScript (**)
.SH SYNTAX
\fBgif2ps\fP [-c] [-i] \fIfilename\fP [-l] [-o \fIfilename\fP] [-s
\fIscale\fP]
.SH DESCRIPTION
\fBgif2ps\fP is a conversion program which converts GIF images to the
PostScript language.
.SH OPTIONS
The '-c' option changes the output to a more space-efficient compact
representation.  The drawback of this option is that the computation
time on the side of the printer is increased by approximately a factor
of five.  It is most useful on a printer with a fast processor and a
slow serial interface, as it reduces the time to actually download the
picture.
.PP
The '-i' option specifies the input filename.  The '-i' itself is
optional, and is provided only for symmetry with the '-o' option.
.PP
The '-l' option renders the image in landscape mode (the image is
rotated 90 degrees from the orientation specified in the GIF file).
.PP
The '-o' option specifies the output filename.  If \fIfilename\fP is
not supplied, the PostScript code will be written to stdout.
.PP
The '-s' option specifies a scale factor, which must be greater than
zero.  \fIScale\fP can be a floating point number, the value defaults
to 1.
.PP
If the GIF image consists solely of grayscale colors, the generated
PostScript output will use the more efficient \fIimage\fP operator to
render the image.
.SH LIMITATIONS
Standard input is not a valid input file in the current
implementation.
.PP
If the GIF image is not a grayscale image, the printer must support
the \fIcolorimage\fP operator.  The generated code will cause a
printer which does not support the operator to print an error message
and quit.
.PP
This program ignores 'local colormaps' in GIF files (see the GIF spec
for details).  It also only displays the first image in GIF files that
have multiple images in them.
.PP
.SH AUTHOR
David Jedlinsky (dcj@decvax.dec.com), based (heavily) on xgif, by John
Bradley (bradley@cis.upenn.edu), which is in turn based (heavily) on
gif2ras.c, by Patrick J. Naughton (naughton@wind.sun.com), a program
that converts GIF pictures to Sun Rasterfiles.
.PP
(*) GIF is a no doubt a trademark of CompuServe, so watch it!
.PP
(**) PostScript is a trademark of Adobe Systems Incorporated.
\End\Of\Shar\
else
  echo "will not over write ./gif2ps.1"
fi
if `test ! -s ./psgif.c`
then
echo "writing ./psgif.c"
cat > ./psgif.c << '\End\Of\Shar\'
/*
 * gif2ps.c - converts GIF pictures to Postscript.
 *
 *  Author:	David Jedlinsky, Digital Equipment Corporation
 *  		(dcj@decvax.dec.com)
 *  		John Bradley, University of Pennsylvania
 *  		(bradley@cis.upenn.edu)
 */

#define MAIN
#include "psgif.h"


/*******************************************/
main(argc, argv)
    int   argc;
    char *argv[];
/*******************************************/
{
    int        	i;
    char	*in, *out;
    FILE      	*outp;
    
    cmd = argv[0];
    in = out = NULL;
    compact = 0; landscape = 0; scale = 1.0;
    
    /*********************Options*********************/

    for (i = 1; i < argc; i++) {

      if (!strncmp(argv[i], "-c", 2)) {		/* compact */
	compact = 1;
	continue;
      }
      
      if (!strncmp(argv[i], "-l", 2)) {		/* landscape */
	landscape = 1;
	continue;
      }

      if (!strncmp(argv[i], "-s", 2)) {		/* scale */
	if (++i >= argc)
	  Syntax(cmd);
	if ((scale = atof(argv[i])) == 0.0) {
	  fprintf(stderr, "%s: Invalid scale.\n", cmd);
	  exit(1);
	}
	continue;
      }
	
      if (!strncmp(argv[i], "-i", 2)) {		/* input */
	if (++i >= argc)
	  Syntax(cmd);
	in = argv[i];
	continue;
      }
	
      if (!strncmp(argv[i], "-o", 2)) {		/* output */
	if (++i >= argc)
	  Syntax(cmd);
	out = argv[i];
	continue;
      }
      
      if (argv[i][0] != '-') {		/* the file name */
	in = argv[i];
	continue;
      }

      Syntax(cmd);
    }

    if (in == NULL) {
      /* in="-"; */
      Syntax(cmd);
    }

    /********** Open File/Write out Header Information********/

    if (out==NULL) {
      out = "stdout";
      outp=stdout;
    } else {
      outp=fopen(out, "w");
    }

    fprintf(outp, "%%!PS-Adobe-1.0\n");
    fprintf(outp, "%%%%Title: %s\n", out);
    fprintf(outp, "%%%%Creator: %s\n", cmd);
    fprintf(outp, "%%%%Pages: (atend)\n");
    fprintf(outp, "%%%%EndComments\n\n");

    /* Add macros needed here. */
    fprintf(outp, "%% GIF macros\n\n");
    
    fprintf(outp, "%%%%EndProlog\n\n");
    

    /***************** Open/Read the File  *****************/
    LoadGIF(in, outp);


    /*************** Write/Close Output File ***************/

    
    fprintf(outp, "%%%%Trailer\n");
    fprintf(outp, "%%%%Pages: 1\n");
    if (outp != stdout)
      if (fclose(outp) == EOF)
	fprintf(stderr, "%s: error closing %s.\n", cmd, out);
  }


/***********************************/
Syntax(cmd)
     char *cmd;
{
    fprintf(stderr,
	    "Usage: %s [-c] [-i] infile [-l] [-s scale] [-o outfile]\n",cmd);
    exit(1);
}


/***********************************/
FatalError (identifier)
       char *identifier;
{
    fprintf(stderr, "%s: %s\n",cmd, identifier);
    exit(-1);
}
\End\Of\Shar\
else
  echo "will not over write ./psgif.c"
fi
if `test ! -s ./psgif.h`
then
echo "writing ./psgif.h"
cat > ./psgif.h << '\End\Of\Shar\'
/*
 *  psgif.h  -  header file for gif2ps, but you probably already knew as much
 */


#define REVDATE   "Rev: 10/26/89"

/* include files */
#include <stdio.h>
#include <math.h>
#include <ctype.h>

#ifndef MAIN
#define WHERE extern
#else
#define WHERE
#endif

typedef unsigned char byte;

void *malloc(), exit(), _exit(), free();

/* global vars */
WHERE int numcols,compact,bw,landscape;
WHERE unsigned long cols[256];
WHERE char *cmd;
WHERE double scale;

#ifndef False
#define False 0
#define True !False
#endif
\End\Of\Shar\
else
  echo "will not over write ./psgif.h"
fi
if `test ! -s ./psgifload.c`
then
echo "writing ./psgifload.c"
cat > ./psgifload.c << '\End\Of\Shar\'
/*
 * psgifload.c  -  based strongly on...
 *
 * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
 *
 * Copyright (c) 1988, 1989 by Patrick J. Naughton
 *
 * Author: Patrick J. Naughton
 * naughton@wind.sun.com
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * This file is provided AS IS with no warranties of any kind.  The author
 * shall have no liability with respect to the infringement of copyrights,
 * trade secrets or any patents by this file or any part thereof.  In no
 * event will the author be liable for any lost revenue or profits or
 * other special, indirect and consequential damages.
 *
 */

#include "psgif.h"

typedef int boolean;

#define NEXTBYTE (*ptr++)
#define IMAGESEP 0x2c
#define INTERLACEMASK 0x40
#define COLORMAPMASK 0x80

FILE *fp;

int BitOffset = 0,              /* Bit Offset of next code */
    XC = 0, YC = 0,             /* Output X and Y coords of current pixel */
    Pass = 0,                   /* Used by output routine if interlaced pic */
    OutCount = 0,               /* Decompressor output 'stack count' */
    RWidth, RHeight,            /* screen dimensions */
    Width, Height,              /* image dimensions */
    LeftOfs, TopOfs,            /* image offset */
    BitsPerPixel,               /* Bits per pixel, read from GIF header */
    BytesPerScanline,           /* bytes per scanline in output raster */
    ColorMapSize,               /* number of colors */
    Background,                 /* background color */
    CodeSize,                   /* Code size, read from GIF header */
    InitCodeSize,               /* Starting code size, used during Clear */
    Code,                       /* Value returned by ReadCode */
    MaxCode,                    /* limiting value for current code size */
    ClearCode,                  /* GIF clear code */
    EOFCode,                    /* GIF end-of-information code */
    CurCode, OldCode, InCode,   /* Decompressor variables */
    FirstFree,                  /* First free code, generated per GIF spec */
    FreeCode,                   /* Decompressor, next free slot in hash
table */
    BitMask,                    /* AND mask for data size */
    ReadMask;                   /* Code AND mask for current code size */

byte FinChar;                   /* Decompressor variable */

boolean Interlace, HasColormap;
boolean Verbose = False;

byte *Image;                    /* The result array */
byte *RawGIF;                   /* The heap array to hold it, raw */
byte *Raster;                   /* The raster data stream, unblocked */

    /* The hash table used by the decompressor */
int Prefix[4096];
int Suffix[4096];

    /* An output array used by the decompressor */
byte OutCode[1025];

    /* The color map, read from the GIF header */
byte Red[256], Green[256], Blue[256], used[256];
int  numused;

char *id = "GIF87a";



/*****************************/
LoadGIF(fname, outp)
     char *fname;
     FILE *outp;
/*****************************/
{
    int            filesize;
    register byte  ch, ch1;
    register byte *ptr, *ptr1;
    register int   i;

    /* stdin won't work with the current implementation! */
/*    if (strcmp(fname,"-") == 0) {
      fp = stdin;
      fname = "<stdin>";
    } else*/
      fp = fopen(fname,"r");

    if (!fp) FatalError("file not found");

    /* find the size of the file */
    if (fseek(fp, 0L, 2) != 0)
      FatalError("couldn't seek to end of file");
    filesize = ftell(fp);
    if (fseek(fp, 0L, 0) != 0)
      FatalError("couldn't seek to start of file");

    if (!(ptr = RawGIF = (byte *) malloc((size_t)filesize)))
        FatalError("not enough memory to read gif file");

    if (!(Raster = (byte *) malloc((size_t)filesize)))
        FatalError("not enough memory to read gif file");

    if (fread((void *)ptr, (size_t)filesize, 1, fp) != (size_t)1)
        FatalError("GIF data read failed");

    if (strncmp((char *)ptr, id, 6))
        FatalError("not a GIF file");

    ptr += 6;

/* Get variables from the GIF screen descriptor */

    ch = NEXTBYTE;
    RWidth = ch + 0x100 * NEXTBYTE;     /* screen dimensions... not used. */
    ch = NEXTBYTE;
    RHeight = ch + 0x100 * NEXTBYTE;

    if (Verbose)
        fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight);

    ch = NEXTBYTE;
    HasColormap = ((ch & COLORMAPMASK) ? True : False);

    BitsPerPixel = (ch & 7) + 1;
    numcols = ColorMapSize = 1 << BitsPerPixel;
    BitMask = ColorMapSize - 1;

    Background = NEXTBYTE;              /* background color... not used. */

    if (NEXTBYTE)               /* supposed to be NULL */
        FatalError("corrupt GIF file (bad screen descriptor)");


/* Read in global colormap. */

    if (HasColormap) {
        if (Verbose)
            fprintf(stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n",
                fname, Width,Height,BitsPerPixel, ColorMapSize);
        for (i = 0; i < ColorMapSize; i++) {
            Red[i] = NEXTBYTE;
            Green[i] = NEXTBYTE;
            Blue[i] = NEXTBYTE;
            used[i] = 0;
          }
        numused = 0;

        }

    else {  /* no colormap in GIF file */
        fprintf(stderr,"%s:  warning!  no colortable in this file. 
Winging it.\n",cmd);
        if (!numcols) numcols=256;
        for (i=0; i<numcols; i++) cols[i] = (unsigned long) i;
        }

/* Check for image seperator */

    if (NEXTBYTE != IMAGESEP)
        FatalError("corrupt GIF file (no image separator)");

/* Now read in values from the image descriptor */

    ch = NEXTBYTE;
    LeftOfs = ch + 0x100 * NEXTBYTE;
    ch = NEXTBYTE;
    TopOfs = ch + 0x100 * NEXTBYTE;
    ch = NEXTBYTE;
    Width = ch + 0x100 * NEXTBYTE;
    ch = NEXTBYTE;
    Height = ch + 0x100 * NEXTBYTE;
    Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);

    if (Verbose)
        fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
                Width, Height, (Interlace) ? "" : "non-");

    else 
        fprintf(stderr, "%s:  %s is %dx%d, %d colors  ",
           cmd, fname, Width,Height,ColorMapSize);
    

/* Note that I ignore the possible existence of a local color map.
 * I'm told there aren't many files around that use them, and the spec
 * says it's defined for future use.  This could lead to an error
 * reading some files. 
 */

/* Start reading the raster data. First we get the intial code size
 * and compute decompressor constant values, based on this code size.
 */

    CodeSize = NEXTBYTE;
    ClearCode = (1 << CodeSize);
    EOFCode = ClearCode + 1;
    FreeCode = FirstFree = ClearCode + 2;

/* The GIF spec has it that the code size is the code size used to
 * compute the above values is the code size given in the file, but the
 * code size used in compression/decompression is the code size given in
 * the file plus one. (thus the ++).
 */

    CodeSize++;
    InitCodeSize = CodeSize;
    MaxCode = (1 << CodeSize);
    ReadMask = MaxCode - 1;

/* Read the raster data.  Here we just transpose it from the GIF array
 * to the Raster array, turning it from a series of blocks into one long
 * data stream, which makes life much easier for ReadCode().
 */

    ptr1 = Raster;
    
    do {
        ch = ch1 = NEXTBYTE;
        while (ch--) *ptr1++ = NEXTBYTE;
        if ((ptr1 - Raster) > filesize) {
          FatalError("corrupt GIF file (unblock)");
        }         
    } while(ch1);

    free((void *)RawGIF);       /* We're done with the raw data now... */

    if (Verbose) {
        fprintf(stderr, "done.\n");
        fprintf(stderr, "Decompressing...");
    }

/* Allocate buffer to hold decompressed image */
    Image = (byte *)malloc((size_t)Width*Height);
    if (!Image) FatalError("not enough memory for Image");
    BytesPerScanline = Width;
    
/* Decompress the file, continuing until you see the GIF EOF code.
 * One obvious enhancement is to add checking for corrupt files here.
 */

    Code = ReadCode();
    while (Code != EOFCode) {

/* Clear code sets everything back to its initial value, then reads the
 * immediately subsequent code as uncompressed data.
 */

        if (Code == ClearCode) {
            CodeSize = InitCodeSize;
            MaxCode = (1 << CodeSize);
            ReadMask = MaxCode - 1;
            FreeCode = FirstFree;
            CurCode = OldCode = Code = ReadCode();
            FinChar = CurCode & BitMask;
            AddToPixel(FinChar);
        }
        else {

/* If not a clear code, then must be data: save same as CurCode and InCode */

            CurCode = InCode = Code;

/* If greater or equal to FreeCode, not in the hash table yet;
 * repeat the last character decoded
 */

            if (CurCode >= FreeCode) {
                CurCode = OldCode;
                OutCode[OutCount++] = FinChar;
            }

/* Unless this code is raw data, pursue the chain pointed to by CurCode
 * through the hash table to its end; each code in the chain puts its
 * associated output code on the output queue.
 */

            while (CurCode > BitMask) {
                if (OutCount > 1024) {
                    fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n");
                    _exit(-1);  /* calling 'exit(-1)' dumps core, so I don't */
                    }
                OutCode[OutCount++] = Suffix[CurCode];
                CurCode = Prefix[CurCode];
            }

/* The last code in the chain is treated as raw data. */

            FinChar = CurCode & BitMask;
            OutCode[OutCount++] = FinChar;

/* Now we put the data out to the Output routine.
 * It's been stacked LIFO, so deal with it that way...
 */

            for (i = OutCount - 1; i >= 0; i--)
                AddToPixel(OutCode[i]);
            OutCount = 0;

/* Build the hash table on-the-fly. No table is stored in the file. */

            Prefix[FreeCode] = OldCode;
            Suffix[FreeCode] = FinChar;
            OldCode = InCode;

/* Point to the next slot in the table.  If we exceed the current
 * MaxCode value, increment the code size unless it's already 12.  If it
 * is, do nothing: the next code decompressed better be CLEAR
 */

            FreeCode++;
            if (FreeCode >= MaxCode) {
                if (CodeSize < 12) {
                    CodeSize++;
                    MaxCode *= 2;
                    ReadMask = (1 << CodeSize) - 1;
                }
            }
        }
        Code = ReadCode();
    }

    free((void *)Raster);

    if (Verbose)
        fprintf(stderr, "done.\n");
    else
        fprintf(stderr,"(of which %d are used)\n",numused);

    if (fp != stdin)
        if (fclose(fp) == EOF)
	  fprintf(stderr, "%s: error closing %s.\n", cmd, fname);

    ColorDicking(fname);

    WriteGIFdata(outp);
}


/* Fetch the next code from the raster data stream.  The codes can be
 * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
 * maintain our location in the Raster array as a BIT Offset.  We compute
 * the byte Offset into the raster array by dividing this by 8, pick up
 * three bytes, compute the bit Offset into our 24-bit chunk, shift to
 * bring the desired code to the bottom, then mask it off and return it. 
 */
ReadCode()
{
int RawCode, ByteOffset;

    ByteOffset = BitOffset / 8;
    RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
    if (CodeSize >= 8)
        RawCode += (0x10000 * Raster[ByteOffset + 2]);
    RawCode >>= (BitOffset % 8);
    BitOffset += CodeSize;
    return(RawCode & ReadMask);
}


AddToPixel(Index)
byte Index;
{
  if (YC<Height)
        *(Image + YC * BytesPerScanline + XC) = Index;

    if (!used[Index]) { used[Index]=1;  numused++; }

/* Update the X-coordinate, and if it overflows, update the Y-coordinate */

    if (++XC == Width) {

/* If a non-interlaced picture, just increment YC to the next scan line. 
 * If it's interlaced, deal with the interlace as described in the GIF
 * spec.
 */

        XC = 0;
        if (!Interlace) YC++;
        else {
            switch (Pass) {
                case 0:
                    YC += 8;
                    if (YC >= Height) {
                        Pass++;
                        YC = 4;
                    }
                break;
                case 1:
                    YC += 8;
                    if (YC >= Height) {
                        Pass++;
                        YC = 2;
                    }
                break;
                case 2:
                    YC += 4;
                    if (YC >= Height) {
                        Pass++;
                        YC = 1;
                    }
                break;
                case 3:
                    YC += 2;
                break;
                default:
                break;
            }
        }
    }
}



/*************************/
ColorDicking(fname)
char *fname;
{
  int i;

  bw = 1;
  
  for (i = 0; i < ColorMapSize; i++)
    if (used[i] && ((Red[i] != Green[i]) || (Red[i] != Blue[i]) ||
                    (Green[i] != Blue[i])))
      bw = 0;

  if (bw)
    fprintf(stderr, "%s: %s is a grayscale image.\n", cmd, fname);
}


/*************************/
WriteGIFdata(fp)
     FILE *fp;
{
  int i, j, count = 1;
  double sx, sy, tx, ty, tmp;
  byte *ptr = Image;

  fprintf(fp, "%%%%Page: 1 1\n\n");

  sx = (double)Width * scale;
  sy = (double)Height * scale;
  
  if (landscape) {
    tx = 306.0 + sy / 2;
    ty = 396.0 - sx / 2;
    tmp = sx;
    sx = sy;
    sy = tmp;
  } else {
    tx = 306.0 - sx / 2;
    ty = 396.0 - sy / 2;
  }
  
  if (!bw) {
    fprintf(fp, "systemdict /colorimage known\n");
    fprintf(fp, "userdict /colorimage known\n");
    fprintf(fp, "or not\n");
    fprintf(fp, "{\n");
    fprintf(fp, "  /Times-Roman findfont 20 scalefont setfont\n");
    fprintf(fp, "  72 72 moveto\n");
    fprintf(fp, "  (This picture requires the colorimage operator.) show\n");
    fprintf(fp, "  showpage stop\n");
    fprintf(fp, "} if\n\n");

    if (compact) {
      fprintf(fp, "/ColorMap %d array def\n", ColorMapSize);
    
      for (i=0; i<ColorMapSize; i++) {
	if (i % 8 == 0)
	  fprintf(fp, "\n");
	fprintf(fp, "<%02x%02x%02x> ", Red[i], Green[i], Blue[i]);
      }
      fprintf(fp, "\nColorMap astore\n\n");
    
      fprintf(fp, "/rgbstr 3 string def\n");
      fprintf(fp, "/nextch 1 string def\n");
      /* Center the image on a 8.5x11 sheet of paper */
      fprintf(fp, "%.1f %.1f translate\n", tx, ty);
      fprintf(fp, "%.1f %.1f scale\n", sx, sy);
      if (landscape)
	fprintf(fp, "90 rotate\n");
      fprintf(fp, "%d %d 8\n", Width, Height);
      fprintf(fp, "[%d 0 0 %d 0 %d]\n", Width, -Height, Height);
      fprintf(fp, "{\n");
      fprintf(fp, "  currentfile nextch readhexstring\n");
      fprintf(fp, "  {\n");
      fprintf(fp, "    0 get\n");
      fprintf(fp, "    ColorMap exch get\n");
      fprintf(fp, "  } {\n");
      fprintf(fp, "    ()\n");
      fprintf(fp, "  } ifelse\n");
      fprintf(fp, "} bind false 3 colorimage\n\n");
    
      ptr = Image;
      for (i=0; i<Height; i++)
	for (j=0; j<Width; j++,ptr++) {
	  fprintf(fp, "%02x", *ptr);
	  if (count++ > 31) {
	    count = 1;
	    fprintf(fp, "\n");
	  }
	}
    } else {
      fprintf(fp, "/rgbstr 256 string def\n");
      fprintf(fp, "%.1f %.1f translate\n", tx, ty);
      fprintf(fp, "%.1f %.1f scale\n", sx, sy);
      if (landscape)
	fprintf(fp, "90 rotate\n");
      fprintf(fp, "%d %d 8\n", Width, Height);
      fprintf(fp, "[%d 0 0 %d 0 %d]\n", Width, -Height, Height);
      fprintf(fp, "{ currentfile rgbstr readhexstring pop }\n");
      fprintf(fp, "bind false 3 colorimage\n\n");
    
      ptr = Image;
      for (i=0; i<Height; i++)
	for (j=0; j<Width; j++,ptr++) {
	  fprintf(fp, "%02x%02x%02x", Red[*ptr], Green[*ptr], Blue[*ptr]);
	  if (count++ > 7) {
	    count = 1;
	    fprintf(fp, "\n");
	  }
	}
    }
  } else { /* B&W */
    fprintf(fp, "/picstr 256 string def\n");
    fprintf(fp, "%.1f %.1f translate\n", tx, ty);
    fprintf(fp, "%.1f %.1f scale\n", sx, sy);
    if (landscape)
      fprintf(fp, "90 rotate\n");
    fprintf(fp, "%d %d 8\n", Width, Height);
    fprintf(fp, "[%d 0 0 %d 0 %d]\n", Width, -Height, Height);
    fprintf(fp, "{ currentfile picstr readhexstring pop }\n");
    fprintf(fp, "bind image\n\n");

    ptr = Image;
    for (i=0; i<Height; i++)
      for (j=0; j<Width; j++,ptr++) {
	fprintf(fp, "%02x", Red[*ptr]);
	if (count++ > 31) {
	  count = 1;
	  fprintf(fp, "\n");
	}
      }
  }
    
  fprintf(fp, "\n\nshowpage\n");
}
\End\Of\Shar\
else
  echo "will not over write ./psgifload.c"
fi
echo "Finished archive 1 of 1"
exit

pjb@tcom.stc.co.uk (Peter J. Bishop) (07/11/90)

Is there someone out there who could mail me the source of gif2ps. I cannot
find it on any of the archive servers to which I have access and I am unable to
connect to any other sites via ftp.

Thanks in advance,

-- 
Peter Bishop.  <pjb@tcom.stc.co.uk> || ...!mcvax!ukc!stc!pjb
STC TSD-E, Engineering Services, 20-22 Edinburgh Way, Harlow. Essex CM20 2DE
Phone : +44 279 626626 x2795

jstewart@rodan.acs.syr.edu (Ace Stewart) (01/11/91)

I haven't had a chance to work with this yet, so I am asking a blind
question. Does anyone know whether or not a color GIF file, using
gif2ps will convert to color PS? Before I go spending money on such
things, I would like to know whether or not anyone has experience in
this...
					Cheers and thanx..Ace
-- 
| Ace Stewart (Jonathan III)                             |A       /\       |
| Affiliation: Eastman Kodak Company. Rochester New York |      _/  \_     |
| Internet/ARPA: jstewart@rodan.acs.syr.edu              |      \_  _/     |
| Bitnet:        jstewart@sunrise.bitnet                 |        /\	  A|