[comp.windows.x] Wanted: GIF to X11 converter

heath@ncrcae.Columbia.NCR.COM (Robert Heath) (01/10/89)

Does anyone have a translator for converting picture files in CompuServe's
Graphic Interchange Format (GIF) to X11 ?

dlw@hpsmtc1.HP.COM (David L. Williams) (01/17/89)

Robert Heath asks:

>Does anyone have a translator for converting picture files in CompuServe's
>Graphic Interchange Format (GIF) to X11 ?

Yes, Jef Poskanzer was kind enuf to implement it in his portable bitmap tools.
It does not handle color gif's I think. You can find it on expo.

-David
"We just need to get Jef a color monitor!"

heath@ncrcae.Columbia.NCR.COM (Robert Heath) (01/18/89)

In article <11880008@hpsmtc1.HP.COM> dlw@hpsmtc1.HP.COM (David L. Williams) writes:
>
>Robert Heath asks:
>
>>Does anyone have a translator for converting picture files in CompuServe's
>>Graphic Interchange Format (GIF) to X11 ?
>
>Yes, Jef Poskanzer was kind enuf to implement it in his portable bitmap tools.
>It does not handle color gif's I think. You can find it on expo.
>
>-David
>"We just need to get Jef a color monitor!"

David,
	I'm still looking.  A couple of people have responded, indicating
that they're developing such a package, but so far noone has come through
with anything concrete.
The two individuals developing conversion packages mentioned that they
will post to one of the comp.sources groups on completion.  

	In the meantime, how do I get up with "Jef Poskanzer's version
on expo" ?    (The mailer on hp-sdd kicked back my e-mail to you!)

	Thanks,
	Robert Heath

	heath@ncrcae.Columbia.NCR.COM
	ncrcae!heath

raveling@vaxb.isi.edu (Paul Raveling) (01/19/89)

In article <11880008@hpsmtc1.HP.COM> dlw@hpsmtc1.HP.COM (David L. Williams) writes:
>
>Robert Heath asks:
>
>>Does anyone have a translator for converting picture files in CompuServe's
>>Graphic Interchange Format (GIF) to X11 ?
>
>Yes, Jef Poskanzer was kind enuf to implement it in his portable bitmap tools.
>It does not handle color gif's I think. You can find it on expo.


	I've hacked an existing GIF-to-Sun converter by Patrick
	Naughton to translate color GIF files into the image format
	we use locally.  This is an old X10 utility, but if anyone
	would like to hack it for X11, or better yet do a sanitary
	conversion, I can supply source.


---------------------
Paul Raveling
Raveling@vaxb.isi.edu

okamoto@hpccc.HP.COM (Jeff Okamoto) (01/20/89)

If you want GIF to X10, Ross Cunniff (cunniff%hpda@hplabs.hp.com)
has written a program to display a color GIF on an X10 display.

A locally-developed tool called gjet (Mark VanMeeter,
markv%hpmwtd@hplabs.hp.com) can take this window and make it suitable
for printing on a PaintJet (or LaserJet, or ThinkJet...).

I've used these to print out some color GIF files.

WARNING: If you like X11, DON'T use the x10tox11 converter to run
this program, unless you like waiting for a LONG time.  Switch back
to X10.

 \      oo	The New Number Who,
  \____|\mm	Jeff Okamoto
  //_//\ \_\	HP Corporate Computing Center
 /K-9/  \/_/	okamoto%hpccc@hplabs.hp.com
/___/_____\	..!hplabs!hpccc!okamoto
-----------	(415) 857-6236

bradley@xmos.cis.upenn.edu (John Bradley) (01/25/89)

>>Robert Heath asks:
>>
>>>Does anyone have a translator for converting picture files in CompuServe's
>>>Graphic Interchange Format (GIF) to X11 ?

I've written a program that displays color and/or monochrome GIF pictures on 
8-bit X11 displays.

It's fairly small, so I'm just going to tack it on at the bottom of this
message.  Sorry if this is considered annoying behavior.  

It's also available for anonymous ftp on dsl.cis.upenn.edu (128.91.2.12).

Also, to any who are interested, there's a slew (30 or so (okay, a *small*
slew)) of GIF pictures also available for anonymous ftp, same place.

I'd appreciate any pointers to more GIF images, as I'm trying to put together
a reasonable collection of these things.

John Bradley  -  bradley@cis.upenn.edu


-----------------------------------(cut here)-----------------------------

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./xgif.man`
then
echo "writing ./xgif.man"
cat > ./xgif.man << '\Rogue\Monster\'
.TH xgif 1X
.SH NAME
xgif \- displays GIF (*) pictures on X11 displays
.SH SYNTAX
\fBxgif\fP [\fIdisplay\fP] [ [-g] \fIgeometry\fP] [-e \fIexpansion\fP]
[-s \fIstrip\fP] [-ns] [\fIfilename\fP]
.SH DESCRIPTION
\fBxgif\fP is an X11 program that displays GIF pictures on an 8-plane 
display.  
.SH OPTIONS
The '-e' option allows you to expand the picture by an integer amount.  For
example, viewing a 320x200 picture with an expansion factor of '2' will 
result in a 640x400 picture, each pixel of which is a 2x2 block.
.PP
You may also specify an expansion of the picture by specifying the size of
the window in the \fIgeometry\fP option.  This also allows you specify 
non-integer expansion factors, and different aspect ratios.  Example:  if
you view a 320x200 picture, but specify a window size of 640x300, the picture
will be expanded by a factor of two along the X-axis, but only by a factor of
1.5 along the Y-axis.
.PP
If you specify both the '-e' option and a window size (via \fIgeometry\fP), 
the '-e' will be ignored.
.PP
The '-s' option allows you specify the number of bits to strip off of the
colors.  The theory runs like this:  if you have 256 unique colors in your
GIF file, you will almost certainly be unable to allocate all of them on an
8-plane display, as a couple colors will already be allocated for the 
window manager, and such.  Setting this option allows you to strip off the
low \fIstrip\fP bits of the R,G,B entries in the GIF colormap.  This will
have the desired effect of making some of the (previously different) colors
the SAME, and you will be able to allocate all the colors you need now.
.PP
You shouldn't ever HAVE to set this option, because if the program is unable
to allocate the required colors, it will try again after incrementing 
\fIstrip\fP.  You can, however save some time, or alternately get neat 
visual effects by setting this option.
.PP
The '-ns' option turns off the 'auto-strip' feature described above.  You
use this to FORCE the program to use as many colors as possible.  The theory
works like this:  if you have 256 unique colors in your GIF file, you will
probably be able to allocate all but a few of them.  Rather than stripping off
bits, decreasing the color resolution for the whole picture uniformly, the
'nostrip' option makes the program set the few unallocatable colors equal to
the 'closest' colors that were allocated.  This may cause nasty 'blotches'
on the picture.  Then again, it might not.  Only way to tell is to try both
with and without the 'auto-strip' 'feature'.
.PP
One DEFINITE drawback of the '-ns' option is that it's only really useful
on the FIRST picture you try to display.  If you try to display two pictures
simultaneously, the first picture will (presumably) use up most (if not ALL)
of the colortable, leaving NO colors for the second picture.  Therefore, the
second (and succeeding pictures) will probably not look very good.  When you
use the 'auto-strip' feature, you will be able to get considerably more 
pictures on the screen simultaneously.  Probably.  Varies wildly, based on 
the actual pictures being displayed.
.PP
Also, it should be noted that if the optional \fIfilename\fP is not supplied,
the program will read the picture from stdin.
.SH LIMITATIONS
You'll require (at least) an 8-plane X11 display.  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
The number of pictures you can display simultaneously varies wildly.  It 
depends on how many colors are in the GIF files, and how many of them are
shared by other GIF files.  Suffice it to say that you can ALWAYS display a
picture, though the colors may or may not be right.  If the program was
unable to get all the desired colors, it will mention that fact.
.PP
Note:  This program points out a bug in the X11R2 server for the IBM RT
Megapel display.  This bug will occasionally cause the colors in a picture
to be wrong, but no 'unable to allocate' message will be printed by the
program.  (Essentially, the problem is a discrepancy between what the 
server THINKS the colormap is, and what the colormap in the hardware 
ACTUALLY is.)
.PP
.SH AUTHOR
John Bradley  -  bradley@cis.upenn.edu
.PP
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!
\Rogue\Monster\
else
  echo "will not over write ./xgif.man"
fi
if `test ! -s ./xgif.h`
then
echo "writing ./xgif.h"
cat > ./xgif.h << '\Rogue\Monster\'
/*
 *  xgif.h  -  header file for xgif, but you probably already knew as much
 */


#define REVDATE   "Rev: 1/20/89"
#define MAXEXPAND 16

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

#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>


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

typedef unsigned char byte;

#define CENTERX(f,x,str) ((x)-XTextWidth(f,str,strlen(str))/2)
#define CENTERY(f,y) ((y)-((f->ascent+f->descent)/2)+f->ascent)


/* X stuff */
WHERE Display       *theDisp;
WHERE int           theScreen, dispcells;
WHERE Colormap      theCmap;
WHERE Window        rootW, mainW;
WHERE GC            theGC;
WHERE unsigned long fcol,bcol;
WHERE Font          mfont;
WHERE XFontStruct   *mfinfo;
WHERE Visual        *theVisual;
WHERE XImage        *theImage, *expImage;

/* global vars */
WHERE int            iWIDE,iHIGH,eWIDE,eHIGH,expand,numcols,strip,nostrip;
WHERE unsigned long  cols[256];
WHERE XColor         defs[256];
WHERE char          *cmd;
\Rogue\Monster\
else
  echo "will not over write ./xgif.h"
fi
if `test ! -s ./xgif.c`
then
echo "writing ./xgif.c"
cat > ./xgif.c << '\Rogue\Monster\'
/*
 * xgif.c - displays GIF pictures on an X11 display
 *
 *  Author:    John Bradley, University of Pennsylvania
 *                (bradley@cis.upenn.edu)
 */

#define MAIN
#include "xgif.h"


/*******************************************/
main(argc, argv)
    int   argc;
    char *argv[];
/*******************************************/
{
    int        i;
    char      *display, *geom, *fname;
    XEvent     event;

    cmd = argv[0];
    display = geom = fname = NULL;
    expImage = NULL;

    expand = 1;  strip = 0;  nostrip = 0;

    /*********************Options*********************/

    for (i = 1; i < argc; i++) {
        char *strind;

        if (argv[i][0] == '=') {
            geom = argv[i];
            continue;
            }

        if (!strncmp(argv[i],"-g",2)) {		/* geometry */
            i++;
            geom = argv[i];
            continue;
            }

        strind = index(argv[i], ':');
        if(strind != NULL) {
            display = argv[i];
            continue;
            }

        if (!strcmp(argv[i],"-e")) {
            i++;
            expand=atoi(argv[i]);
            continue;
            }

        if (!strcmp(argv[i],"-s")) {
            i++;
            strip=atoi(argv[i]);
            continue;
            }

        if (!strcmp(argv[i],"-ns")) {
            nostrip++;
            continue;
            }

        if (argv[i][0] != '-') {		/* the file name */
            fname = argv[i];
            continue;
            }

        Syntax(cmd);
    }

    if (fname==NULL) fname="-";
    if (expand<1 || expand>MAXEXPAND) Syntax(cmd);
    if (strip<0 || strip>7) Syntax(cmd);

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

    /* Open up the display. */

    if ( (theDisp=XOpenDisplay(display)) == NULL) {
        fprintf(stderr, "%s: Can't open display\n",argv[0]);
        exit(1);
        }

    theScreen = DefaultScreen(theDisp);
    theCmap   = DefaultColormap(theDisp, theScreen);
    rootW     = RootWindow(theDisp,theScreen);
    theGC     = DefaultGC(theDisp,theScreen);
    fcol      = WhitePixel(theDisp,theScreen);
    bcol      = BlackPixel(theDisp,theScreen);
    theVisual = DefaultVisual(theDisp,theScreen);

    dispcells = DisplayCells(theDisp, theScreen);
    if (dispcells<255) 
        FatalError("This program requires an 8-plane display, at least.");


    /****************** Open/Read the File  *****************/
    LoadGIF(fname);
    iWIDE = theImage->width;  iHIGH = theImage->height;

    eWIDE = iWIDE * expand;  eHIGH = iHIGH * expand;
    if (eWIDE > DisplayWidth(theDisp,theScreen)) 
        eWIDE = DisplayWidth(theDisp,theScreen);
    if (eHIGH > DisplayHeight(theDisp,theScreen)) 
        eHIGH = DisplayHeight(theDisp,theScreen);

    /**************** Create/Open X Resources ***************/
    if ((mfinfo = XLoadQueryFont(theDisp,"variable"))==NULL)
       FatalError("couldn't open 'variable' font\n");
    mfont=mfinfo->fid;
    XSetFont(theDisp,theGC,mfont);
    XSetForeground(theDisp,theGC,fcol);
    XSetBackground(theDisp,theGC,bcol);

    CreateMainWindow(cmd,geom,argc,argv);
    Resize(eWIDE,eHIGH);

    XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
                               | StructureNotifyMask);
    XMapWindow(theDisp,mainW);

    /**************** Main loop *****************/
    while (1) {
        XNextEvent(theDisp, &event);
        HandleEvent(&event);
        }
}



/****************/
HandleEvent(event)
    XEvent *event;
/****************/
{
    switch (event->type) {
        case Expose: {
            XExposeEvent *exp_event = (XExposeEvent *) event;

            if (exp_event->window==mainW) 
                DrawWindow(exp_event->x,exp_event->y,
                           exp_event->width, exp_event->height);
            }
            break;

        case KeyPress: {
            XKeyEvent *key_event = (XKeyEvent *) event;
            char buf[128];
            KeySym ks;
            XComposeStatus status;

            XLookupString(key_event,buf,128,&ks,&status);
            if (buf[0]=='q' || buf[0]=='Q') Quit();
            }
            break;

        case ConfigureNotify: {
            XConfigureEvent *conf_event = (XConfigureEvent *) event;

            if (conf_event->window == mainW && 
                 (conf_event->width != eWIDE || conf_event->height != eHIGH))
                Resize(conf_event->width, conf_event->height);
            }
            break;


        case CirculateNotify:
        case MapNotify:
        case DestroyNotify:
        case GravityNotify:
        case ReparentNotify:
        case UnmapNotify:       break;

        default:
            printf("event type=%ld\n",event->type); 
            FatalError("Unexpected X_Event");

        }  /* end of switch */
}


/***********************************/
Syntax()
{
    printf("Usage: %s filename [=geometry | -geometry geom] [display]\n",cmd);
    printf("       [-e 1..%d] [-s 0-7] [-ns]\n",MAXEXPAND);
    exit(1);
}


/***********************************/
FatalError (identifier)
       char *identifier;
{
    fprintf(stderr, "%s: %s\n",cmd, identifier);
    exit(-1);
}


/***********************************/
Quit()
{
    exit(0);
}


/***********************************/
DrawWindow(x,y,w,h)
{
    XPutImage(theDisp,mainW,theGC,expImage,x,y,x,y,w,h);
}


/***********************************/
Resize(w,h)
int w,h;
{
    int  ix,iy,ex,ey;
    byte *ximag,*ilptr,*ipptr,*elptr,*epptr;
    static char *rstr = "Resizing Image.  Please wait...";

    /* warning:  this code'll only run machines where int=32-bits */

    if (w==iWIDE && h==iHIGH) {		/* very special case */
        if (expImage != theImage) {
            if (expImage) XDestroyImage(expImage);
            expImage = theImage;
            eWIDE = iWIDE;  eHIGH = iHIGH;
            }
        }

    else {				/* have to do some work */
        /* if it's a big image, this'll take a while.  mention it */
        if (w*h>(500*500)) {
            XDrawImageString(theDisp,mainW,theGC,CENTERX(mfinfo,w/2,rstr),
                  CENTERY(mfinfo,h/2),rstr, strlen(rstr));
            XFlush(theDisp);
            }

	/* first, kill the old expImage, if one exists */
	if (expImage && expImage != theImage) XDestroyImage(expImage);

        /* create expImage of the appropriate size */
        
        eWIDE = w;  eHIGH = h;
        ximag = (byte *) malloc(w*h);
        expImage = XCreateImage(theDisp,theVisual,8,ZPixmap,0,ximag,
                        eWIDE,eHIGH,8,eWIDE);

        if (!ximag || !expImage) {
            fprintf(stderr,"ERROR: unable to create a %dx%d image\n",w,h);
            exit(0);
            }

        elptr = epptr = (byte *) expImage->data;

        for (ey=0;  ey<eHIGH;  ey++, elptr+=eWIDE) {
            iy = (iHIGH * ey) / eHIGH;
            epptr = elptr;
            ilptr = (byte *) theImage->data + (iy * iWIDE);
            for (ex=0;  ex<eWIDE;  ex++,epptr++) {
                ix = (iWIDE * ex) / eWIDE;
                ipptr = ilptr + ix;
                *epptr = *ipptr;
                }
            }
        }
}
                

/***********************************/
CreateMainWindow(name,geom,argc,argv)
    char *name,*geom,**argv;
    int   argc;
{
    XSetWindowAttributes xswa;
    unsigned int xswamask;
    XSizeHints hints;
    int i,x,y,w,h;

    x=y=w=h=1;
    i=XParseGeometry(geom,&x,&y,&w,&h);
    if (i&WidthValue)  eWIDE = w;
    if (i&HeightValue) eHIGH = h;

    if (i&XValue || i&YValue) hints.flags = USPosition;  
                         else hints.flags = PPosition;

    hints.flags |= USSize;

    if (i&XValue && i&XNegative) 
        x = XDisplayWidth(theDisp,theScreen)-eWIDE-abs(x);
    if (i&YValue && i&YNegative) 
        y = XDisplayHeight(theDisp,theScreen)-eHIGH-abs(y);

    hints.x=x;             hints.y=y;
    hints.width  = eWIDE;  hints.height = eHIGH;

    xswa.background_pixel = bcol;
    xswa.border_pixel     = fcol;
    xswamask = CWBackPixel | CWBorderPixel;

    mainW = XCreateWindow(theDisp,rootW,x,y,eWIDE,eHIGH,2,0,CopyFromParent,
                          CopyFromParent, xswamask, &xswa);

    XSetStandardProperties(theDisp,mainW,"xgif","xgif",None,
                            argv,argc,&hints);

    if (!mainW) FatalError("Can't open main window");

}


\Rogue\Monster\
else
  echo "will not over write ./xgif.c"
fi
if `test ! -s ./xgifload.c`
then
echo "writing ./xgifload.c"
cat > ./xgifload.c << '\Rogue\Monster\'
/*
 * xgifload.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 "xgif.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 */
    FinChar,			/* Decompressor variable */
    BitMask,			/* AND mask for data size */
    ReadMask;			/* Code AND mask for current code size */

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 */
int OutCode[1025];

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

char *id = "GIF87a";



/*****************************/
LoadGIF(fname)
  char *fname;
/*****************************/
{
    int            filesize;
    register byte  ch, ch1;
    register byte *ptr, *ptr1;
    register int   i,j;
    static byte    lmasks[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
    byte           lmask;

    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 */
    fseek(fp, 0L, 2);
    filesize = ftell(fp);
    fseek(fp, 0L, 0);

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

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

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

    if (strncmp(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;
	    }

        /* Allocate the X colors for this picture */

        if (nostrip)  {   /* nostrip was set.  try REAL hard to do it */
            j = 0;
            lmask = lmasks[strip];
            for (i=0; i<numcols; i++) {
                defs[i].red   = (Red[i]  &lmask)<<8;
                defs[i].green = (Green[i]&lmask)<<8;
                defs[i].blue  = (Blue[i] &lmask)<<8;
                defs[i].flags = DoRed | DoGreen | DoBlue;
                if (!XAllocColor(theDisp,theCmap,&defs[i])) { 
                    j++;  defs[i].pixel = 0xffff;
                    }
                cols[i] = defs[i].pixel;
                }

            if (j) {		/* failed to pull it off */
                XColor ctab[256];

                fprintf(stderr,"failed to allocate %d out of %d colors.  Trying extra hard.\n",j,numcols);
                
                /* read in the color table */
                for (i=0; i<numcols; i++) ctab[i].pixel = i;
                XQueryColors(theDisp,theCmap,ctab,numcols);
                
                for (i=0; i<numcols; i++)
                    if (cols[i] == 0xffff) {		/* an unallocated pixel */
                        int d, mdist, close;
                        unsigned long r,g,b;

                        mdist = 100000;   close = -1;
                        r =  Red[i];
                        g =  Green[i];
                        b =  Blue[i];
                        for (j=0; j<numcols; j++) {
                            d = abs(r - (ctab[j].red>>8)) +
                                abs(g - (ctab[j].green>>8)) +
                                abs(b - (ctab[j].blue>>8));
                            if (d<mdist) { mdist=d; close=j; }
                            }
                        if (close<0) FatalError("simply can't do it.  Sorry.");
                        bcopy(&defs[close],&defs[i],sizeof(XColor));
                        cols[i] = ctab[close].pixel;
                        }
                }
            }

        else {          /* strip wasn't set, do the best auto-strip */
            j = 0;
            while (strip<8) {
                lmask = lmasks[strip];
                for (i=0; i<numcols; i++) {
                    defs[i].red   = (Red[i]  &lmask)<<8;
                    defs[i].green = (Green[i]&lmask)<<8;
                    defs[i].blue  = (Blue[i] &lmask)<<8;
                    defs[i].flags = DoRed | DoGreen | DoBlue;
                    if (!XAllocColor(theDisp,theCmap,&defs[i])) break;
                    cols[i] = defs[i].pixel;
                    }
                if (i<numcols) {		/* failed */
                    strip++;  j++;
                    XFreeColors(theDisp,theCmap,cols,i,0L);
                    }
                else break;
                }

            if (j && strip<8)
                fprintf(stderr,"%s:  %s stripped %d bits\n",cmd,fname,strip);

            if (strip==8) {
                fprintf(stderr,"UTTERLY failed to allocate the desired colors.  Sorry.\n");
                for (i=0; i<numcols; i++) cols[i]=i;
                }
            }
        }

    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, %sinterlaced\n",
	   cmd, fname, Width,Height,ColorMapSize,(Interlace) ? "" : "non-");
    

/* 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 ((Raster - ptr1) > filesize)
	    FatalError("corrupt GIF file (unblock)");
    } while(ch1);

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

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


/* Allocate the X Image */
    Image = (byte *) malloc(Width*Height);
    if (!Image) FatalError("not enough memory for XImage");

    theImage = XCreateImage(theDisp,theVisual,8,ZPixmap,0,Image,
                         Width,Height,8,Width);
    if (!theImage) FatalError("unable to create XImage");

    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)
		    FatalError("corrupt GIF file (OutCount)");
		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(Raster);

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

    if (fp != stdin)
	fclose(fp);
}


/* 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;
{
    *(Image + YC * BytesPerScanline + XC) = cols[Index&(numcols-1)];

/* 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.  Put the decoded scan line out to the screen if we haven't gone
 * past the bottom of it
 */

	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;
	    }
	}
    }
}
\Rogue\Monster\
else
  echo "will not over write ./xgifload.c"
fi
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\Rogue\Monster\'
XLIB = -lX11
CFLAGS = -O

OBJS = xgif.o xgifload.o

all: xgif

xgif: $(OBJS)
	cc $(CFLAGS) -o xgif $(OBJS) $(XLIB) $(CLIBS)

clean:
	rm -f $(OBJS)


\Rogue\Monster\
else
  echo "will not over write ./Makefile"
fi
echo "Finished archive 1 of 1"
exit