1 #ident "@(#)gif.c	1.5 91/04/01 XGRASP"
2 /*-
3  * gif.c - routine to load GIF images (hacked from gif2ras).
4  *
5  * Copyright (c) 1991 by Patrick J. Naughton
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation for any purpose and without fee is hereby granted,
9  * provided that the above copyright notice appear in all copies and that
10  * both that copyright notice and this permission notice appear in
11  * supporting documentation.
12  *
13  * This file is provided AS IS with no warranties of any kind.  The author
14  * shall have no liability with respect to the infringement of copyrights,
15  * trade secrets or any patents by this file or any part thereof.  In no
16  * event will the author be liable for any lost revenue or profits or
17  * other special, indirect and consequential damages.
18  *
19  * Comments and additions should be sent to the author:
20  *
21  *                     Patrick J. Naughton
22  *                     Sun Microsystems
23  *                     2550 Garcia Ave, MS 10-20
24  *                     Mountain View, CA 94043
25  *                     (415) 336-1080
26  *
27  */
28 
29 #include "grasp.h"
30 
31 #define NEXTBYTE (*ptr++)
32 #define IMAGESEP 0x2c
33 #define INTERLACEMASK 0x40
34 #define COLORMAPMASK 0x80
35 
36 static int  BitOffset,	/* Bit Offset of next code */
37             XC, YC,	/* Output X and Y coords of current pixel */
38             Pass,	/* Used by output routine if interlaced pic */
39             OutCount,	/* Decompressor output 'stack count' */
40             RWidth, RHeight,	/* screen dimensions */
41             Width, Height,	/* image dimensions */
42             LeftOfs, TopOfs,	/* image offset */
43             BitsPerPixel,	/* Bits per pixel, read from GIF header */
44             ColorMapSize,	/* number of colors */
45             CodeSize,	/* Code size, read from GIF header */
46             InitCodeSize,	/* Starting code size, used during Clear */
47             LZWCode,	/* Value returned by ReadCode */
48             MaxCode,	/* limiting value for current code size */
49             ClearCode,	/* GIF clear code */
50             EOFCode,	/* GIF end-of-information code */
51             CurCode, OldCode, InCode,	/* Decompressor variables */
52             FirstFree,	/* First free code, generated per GIF spec */
53             FreeCode,	/* Decompressor, next free slot in hash table */
54             FinChar,	/* Decompressor variable */
55             BitMask,	/* AND mask for data size */
56             ReadMask,	/* Code AND mask for current code size */
57             Interlace, HasColormap;
58 
59 static u_char *Image;	/* The result array */
60 static u_char *RawGIF;	/* The heap array to hold it, raw */
61 static u_char *Raster;	/* The raster data stream, unblocked */
62 
63  /* The hash table used by the decompressor */
64 static int  Prefix[4096];
65 static int  Suffix[4096];
66 
67  /* An output array used by the decompressor */
68 static int  OutCode[1025];
69 
70 static char *id = "GIF87a";
71 
72 
73 /* Fetch the next code from the raster data stream.  The codes can be
74  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
75  * maintain our location in the Raster array as a BIT Offset.  We compute
76  * the byte Offset into the raster array by dividing this by 8, pick up
77  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
78  * bring the desired code to the bottom, then mask it off and return it.
79  */
80 static int
ReadCode()81 ReadCode()
82 {
83     int         RawCode, ByteOffset;
84 
85     ByteOffset = BitOffset / 8;
86     RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
87     if (CodeSize >= 8)
88 	RawCode += (0x10000 * Raster[ByteOffset + 2]);
89     RawCode >>= (BitOffset % 8);
90     BitOffset += CodeSize;
91     return (RawCode & ReadMask);
92 }
93 
94 static void
AddToPixel(Index)95 AddToPixel(Index)
96     u_char      Index;
97 {
98     *(Image + YC * Width + XC) = Index;
99 
100 /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
101 
102     if (++XC == Width) {
103 
104 /* If a non-interlaced picture, just increment YC to the next scan line.
105  * If it's interlaced, deal with the interlace as described in the GIF
106  * spec.  Put the decoded scan line out to the screen if we haven't gone
107  * past the bottom of it
108  */
109 
110 	XC = 0;
111 	if (!Interlace)
112 	    YC++;
113 	else {
114 	    switch (Pass) {
115 	    case 0:
116 		YC += 8;
117 		if (YC >= Height) {
118 		    Pass++;
119 		    YC = 4;
120 		}
121 		break;
122 	    case 1:
123 		YC += 8;
124 		if (YC >= Height) {
125 		    Pass++;
126 		    YC = 2;
127 		}
128 		break;
129 	    case 2:
130 		YC += 4;
131 		if (YC >= Height) {
132 		    Pass++;
133 		    YC = 1;
134 		}
135 		break;
136 	    case 3:
137 		YC += 2;
138 		break;
139 	    default:
140 		break;
141 	    }
142 	}
143     }
144 }
145 
146 
147 ImageStruct *
readgifimage(fp,dirent)148 readgifimage(fp, dirent)
149     FILE       *fp;
150     FilenameStruct *dirent;
151 {
152     ImageStruct *im;
153     XImage     *xim;
154     int         filesize;
155     u_char      ch, ch1;
156     u_char     *ptr, *ptr1;
157     int         i;
158 
159     BitOffset = 0;
160     XC = 0;
161     YC = 0;
162     Pass = 0;
163     OutCount = 0;
164 
165     im = (ImageStruct *) malloc(sizeof(ImageStruct));
166 
167     fseek(fp, dirent->offset, 0);
168 
169     filesize = GetLong(fp);	/* length of whole image file... */
170 
171     im->name = strtok(strdup(dirent->fname), ".");
172     im->type = EXT_GIF;
173     im->xoff = 0;
174     im->yoff = 0;
175 
176     if (!(ptr = RawGIF = (u_char *) malloc(filesize)))
177 	error("%s: not enough memory to read gif file.\n", NULL);
178 
179     if (!(Raster = (u_char *) malloc(filesize)))
180 	error("%s: not enough memory to read gif file.\n", NULL);
181 
182     if (fread(ptr, filesize, 1, fp) != 1)
183 	error("%s: GIF data read failed\n", NULL);
184 
185     if (strncmp(ptr, id, 6)) {
186 	free(im->name);
187 	free(im);
188 	free(Raster);
189 	free(ptr);
190 	return (ImageStruct *) readimage(fp, dirent, EXT_PIC);
191     }
192     ptr += 6;
193 
194 /* Get variables from the GIF screen descriptor */
195 
196     ch = NEXTBYTE;
197     RWidth = ch + 0x100 * NEXTBYTE;	/* screen dimensions... not used. */
198     ch = NEXTBYTE;
199     RHeight = ch + 0x100 * NEXTBYTE;
200 
201     ch = NEXTBYTE;
202     HasColormap = ((ch & COLORMAPMASK) ? True : False);
203 
204     BitsPerPixel = (ch & 7) + 1;
205     im->cmaplen = 1 << BitsPerPixel;
206     BitMask = im->cmaplen - 1;
207 
208     ch = NEXTBYTE;	/* background color... not used. */
209 
210     if (NEXTBYTE)	/* supposed to be NULL */
211 	error("%s: %s is a corrupt GIF file (nonull).\n", im->name);
212 
213 /* Read in global colormap. */
214 
215     if (HasColormap) {
216 	unsigned long pmasks;
217 	u_long      pixels[256];
218 
219 	im->cmap = XCreateColormap(dsp, win, vis, AllocNone);
220 	XAllocColorCells(dsp, im->cmap, True, &pmasks, 0, pixels, im->cmaplen);
221 
222 	for (i = 0; i < im->cmaplen; i++) {
223 	    im->colors[i].pixel = pixels[i];
224 	    im->colors[i].red = NEXTBYTE << 8;
225 	    im->colors[i].green = NEXTBYTE << 8;
226 	    im->colors[i].blue = NEXTBYTE << 8;
227 	    im->colors[i].flags = DoRed | DoGreen | DoBlue;
228 
229 	    if (imverbose) {
230 		printf("%02x%02x%02x ",
231 		       im->colors[i].red >> 8,
232 		       im->colors[i].green >> 8,
233 		       im->colors[i].blue >> 8);
234 		if (!((i + 1) % 8))
235 		    printf("\n");
236 	    }
237 	}
238 	XStoreColors(dsp, im->cmap, im->colors, im->cmaplen);
239     } else
240 	im->cmap = (Colormap) 0;
241 
242 /* Check for image seperator */
243 
244     if (NEXTBYTE != IMAGESEP)
245 	error("%s: %s is a corrupt GIF file (nosep).\n", im->name);
246 /* Now read in values from the image descriptor */
247 
248     ch = NEXTBYTE;
249     LeftOfs = ch + 0x100 * NEXTBYTE;
250     ch = NEXTBYTE;
251     TopOfs = ch + 0x100 * NEXTBYTE;
252     ch = NEXTBYTE;
253     Width = ch + 0x100 * NEXTBYTE;
254     ch = NEXTBYTE;
255     Height = ch + 0x100 * NEXTBYTE;
256     Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
257 
258     if (verbose)
259 	fprintf(stderr, "%s: (GIF) %dx%dx%d %s\n",
260 		im->name, Width, Height, 8,
261 		(Interlace) ? "Interlaced" : "");
262 
263 /* Note that I ignore the possible existence of a local color map.
264  * I'm told there aren't many files around that use them, and the spec
265  * says it's defined for future use.  This could lead to an error
266  * reading some files.
267  */
268 
269 /* Start reading the raster data. First we get the intial code size
270  * and compute decompressor constant values, based on this code size.
271  */
272 
273     CodeSize = NEXTBYTE;
274     ClearCode = (1 << CodeSize);
275     EOFCode = ClearCode + 1;
276     FreeCode = FirstFree = ClearCode + 2;
277 
278 /* The GIF spec has it that the code size is the code size used to
279  * compute the above values is the code size given in the file, but the
280  * code size used in compression/decompression is the code size given in
281  * the file plus one. (thus the ++).
282  */
283 
284     CodeSize++;
285     InitCodeSize = CodeSize;
286     MaxCode = (1 << CodeSize);
287     ReadMask = MaxCode - 1;
288 
289 /* Read the raster data.  Here we just transpose it from the GIF array
290  * to the Raster array, turning it from a series of blocks into one long
291  * data stream, which makes life much easier for ReadCode().
292  */
293 
294     ptr1 = Raster;
295     do {
296 	ch = ch1 = NEXTBYTE;
297 	while (ch--)
298 	    *ptr1++ = NEXTBYTE;
299 	if ((Raster - ptr1) > filesize)
300 	    error("%s: %s is a corrupt GIF file (unblock).\n", im->name);
301     } while (ch1);
302 
303     free(RawGIF);	/* We're done with the raw data now... */
304 
305     Image = (u_char *) malloc(Width * Height);
306     if (!Image)
307 	error("%s: malloc failed on image data.\n");
308 
309 /* Decompress the file, continuing until you see the GIF EOF code.
310  * One obvious enhancement is to add checking for corrupt files here.
311  */
312 
313     LZWCode = ReadCode();
314     while (LZWCode != EOFCode) {
315 
316 /* Clear code sets everything back to its initial value, then reads the
317  * immediately subsequent code as uncompressed data.
318  */
319 
320 	if (LZWCode == ClearCode) {
321 	    CodeSize = InitCodeSize;
322 	    MaxCode = (1 << CodeSize);
323 	    ReadMask = MaxCode - 1;
324 	    FreeCode = FirstFree;
325 	    CurCode = OldCode = LZWCode = ReadCode();
326 	    FinChar = CurCode & BitMask;
327 	    AddToPixel(FinChar);
328 	} else {
329 
330 /* If not a clear code, then must be data: save same as CurCode and InCode */
331 
332 	    CurCode = InCode = LZWCode;
333 
334 /* If greater or equal to FreeCode, not in the hash table yet;
335  * repeat the last character decoded
336  */
337 
338 	    if (CurCode >= FreeCode) {
339 		CurCode = OldCode;
340 		OutCode[OutCount++] = FinChar;
341 	    }
342 /* Unless this code is raw data, pursue the chain pointed to by CurCode
343  * through the hash table to its end; each code in the chain puts its
344  * associated output code on the output queue.
345  */
346 
347 	    while (CurCode > BitMask) {
348 		if (OutCount > 1024) {
349 		    fprintf(stderr, "%s is a corrupt GIF file (OutCount).\n",
350 			    im->name);
351 		    goto error_exit;
352 		}
353 		OutCode[OutCount++] = Suffix[CurCode];
354 		CurCode = Prefix[CurCode];
355 	    }
356 
357 /* The last code in the chain is treated as raw data. */
358 
359 	    FinChar = CurCode & BitMask;
360 	    OutCode[OutCount++] = FinChar;
361 
362 /* Now we put the data out to the Output routine.
363  * It's been stacked LIFO, so deal with it that way...
364  */
365 
366 	    for (i = OutCount - 1; i >= 0; i--)
367 		AddToPixel(OutCode[i]);
368 	    OutCount = 0;
369 
370 /* Build the hash table on-the-fly. No table is stored in the file. */
371 
372 	    Prefix[FreeCode] = OldCode;
373 	    Suffix[FreeCode] = FinChar;
374 	    OldCode = InCode;
375 
376 /* Point to the next slot in the table.  If we exceed the current
377  * MaxCode value, increment the code size unless it's already 12.  If it
378  * is, do nothing: the next code decompressed better be CLEAR
379  */
380 
381 	    FreeCode++;
382 	    if (FreeCode >= MaxCode) {
383 		if (CodeSize < 12) {
384 		    CodeSize++;
385 		    MaxCode *= 2;
386 		    ReadMask = (1 << CodeSize) - 1;
387 		}
388 	    }
389 	}
390 	LZWCode = ReadCode();
391     }
392 error_exit:
393 
394     free(Raster);
395 
396     im->w = Width;
397     im->h = Height;
398     im->d = 8;
399     xim = XCreateImage(dsp, vis, im->d, ZPixmap, 0, Image,
400 		       im->w, im->h, 8, im->w);
401     im->pix = XCreatePixmap(dsp, win, im->w, im->h, 8);
402     XPutImage(dsp, im->pix, gc, xim, 0, 0, 0, 0, im->w, im->h);
403     XSync(dsp, False);
404     free(Image);
405     return im;
406 }
407