1 //
2 // The loading routine for gif images was extracted from the gif-loader
3 // of the xv-package. It was enclosed into a C++-class and enhanced for some
4 // features to query possible extension data, which can be used to store
5 // the additional setup informations and copyright notes.
6 //
7 // Here is the original note, that once was contained in the loader
8 //
9 
10 /*
11  * xvgif.c  -  GIF loading code for 'xv'.  Based strongly on...
12  *
13  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
14  *
15  * Copyright (c) 1988, 1989 by Patrick J. Naughton
16  *
17  * Author: Patrick J. Naughton
18  * naughton@wind.sun.com
19  *
20  * Permission to use, copy, modify, and distribute this software and its
21  * documentation for any purpose and without fee is hereby granted,
22  * provided that the above copyright notice appear in all copies and that
23  * both that copyright notice and this permission notice appear in
24  * supporting documentation.
25  *
26  * This file is provided AS IS with no warranties of any kind.  The author
27  * shall have no liability with respect to the infringement of copyrights,
28  * trade secrets or any patents by this file or any part thereof.  In no
29  * event will the author be liable for any lost revenue or profits or
30  * other special, indirect and consequential damages.
31  *
32  */
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include "gif_image.H"
39 
40 #define	False	0
41 #define	True	1
42 #define	DEBUG	0
43 
44 #define	quiet				1
45 #define	minpix			10
46 #define	fastinfo_flag	0
47 
AddData(char * ndata,int nlen)48 void Extension::AddData( char *ndata, int nlen ) {
49 	char *hdata=new char[len+nlen];
50 	memcpy(hdata,data,len);
51 	memcpy(hdata+len,ndata,nlen);
52 	delete data;
53 	len+=nlen;
54 	data=hdata;
55 }
56 
GifImage(const char * filename,int autocrop)57 GifImage::GifImage(const char *filename, int autocrop )
58 : lockcount(0) {
59 	first=0;
60 	LoadGIF( filename );
61 	const char *pos = strrchr(filename,'/');
62 	if (pos)		name=strdup(pos+1);
63 	else			name=strdup(filename);
64 
65 	if (autocrop&&!fastinfo_flag)	CropImage();
66 }
67 
GifImage()68 GifImage::GifImage() {
69 	first=0;
70 	name=strdup("dummy");
71 	lockcount=0;
72 	ColorMapSize=128;
73 	for (int i=0;i<128;i++) {
74 		Red[i]   = 255 * ((i>>5)&0x03) / 3;
75 		Green[i] = 255 * ((i>>2)&0x07) / 7;
76 		Blue[i]  = 255 *      (i&0x03) / 3;
77 	}
78 	width =1;
79 	height=1;
80 	data  =(byte*)malloc(1);
81 }
82 
~GifImage()83 GifImage::~GifImage() {
84 	if (lockcount) {
85 		fprintf( stderr, "ERROR: GifImage::~GifImage: image still locked\n" );
86 	}
87 
88 	if (first)	delete first;
89 
90 	free(name);
91 	CloseGif();
92 }
93 
GetExtensionData(unsigned char code)94 const char *GifImage::GetExtensionData( unsigned char code ) {
95 Extension	*current;
96 
97 	for (current=first;current;current=current->next) {
98 		if (current->code==code)		return current->data;
99 	}
100 	return 0;
101 }
102 
GetColor(int id,unsigned short * red,unsigned short * green,unsigned short * blue)103 int GifImage::GetColor(int id, unsigned short *red, unsigned short *green, unsigned short *blue) {
104 	*red  =Red[id]   | Red[id]<<8;
105 	*green=Green[id] | Green[id]<<8;
106 	*blue =Blue[id]  | Blue[id]<<8;
107 	return 0;
108 }
109 
Recolor(class GifImage * gif_p)110 void GifImage::Recolor( class GifImage *gif_p ) {
111 int mapper[256];
112 int i,j;
113 
114 	for (i=0;i<ColorMapSize;i++) {
115 		int	min_j = 0;
116 		int	min_d = 0x7fffffff;
117 		for (j=0;j<gif_p->ColorMapSize;j++) {
118 			int dr = (gif_p->Red[j]  -Red[i]);
119 			int dg = (gif_p->Green[j]-Green[i]);
120 			int db = (gif_p->Blue[j] -Blue[i]);
121 			int d = dr*dr + dg*dg + db*db;
122 			if (d<min_d) {
123 				min_d = d;
124 				min_j = j;
125 			}
126 		}
127 		mapper[i]=min_j;
128 	}
129 	for (i=0;i<width*height;i++) {
130 		data[i] = mapper[data[i]];
131 	}
132 
133 	for (j=0;j<gif_p->ColorMapSize;j++) {
134 		Red[j]   = gif_p->Red[j];
135 		Green[j] = gif_p->Green[j];
136 		Blue[j]  = gif_p->Blue[j];
137 	}
138 	ColorMapSize = gif_p->ColorMapSize;
139 }
140 
Rotate90()141 void GifImage::Rotate90() {
142 byte	*ndata;
143 int	help;
144 
145 	if (!(ndata = (byte *)malloc(width*height))) {
146 		fprintf(stderr,"not enough memory to flip image");
147 		exit(-1);
148 	}
149 
150 	for (int y=0;y<height;y++) {
151 		for (int x=0;x<width;x++) {
152 			ndata[(height-y-1)+x*height] = data[x+y*width];
153 		}
154 	}
155 
156 	help=width; width=height; height=help;
157 	free(data);
158 	data=ndata;
159 }
160 
AddAt(int x21,int y21,class GifImage * gif_p)161 void GifImage::AddAt( int x21, int y21, class GifImage *gif_p ) {
162 int x22=x21+gif_p->Width();
163 int y22=y21+gif_p->Height();
164 
165 int nwidth,nheight;
166 byte *ndata=0;
167 
168 	if (x21>=0) {
169 		if (x22>Width())		nwidth=x22;
170 		else						nwidth=Width();
171 	}
172 	else {
173 		if (x22>Width())		nwidth=gif_p->Width();
174 		else						nwidth=(-x21)+Width();
175 	}
176 	if (y21>=0) {
177 		if (y22>Height())		nheight=y22;
178 		else						nheight=Height();
179 	}
180 	else {
181 		if (y22>Height())		nheight=gif_p->Height();
182 		else						nheight=(-y21)+Height();
183 	}
184 
185 	if (nwidth>Width()||nheight>Height()) {
186 		if (!(ndata = (byte *)malloc(nwidth*nheight))) {
187 			fprintf(stderr,"not enough memory for image");
188 			exit(-1);
189 		}
190 
191 	/* move first image */
192 		memset( ndata, 0, nwidth*nheight );
193 		int offx = (x21<0)?-x21:0;
194 		int offy = (y21<0)?-y21:0;
195 		for (int y=0;y<Height();y++) {
196 			memcpy( ndata+offx+(offy+y)*nwidth, data+y*Width(), Width() );
197 		}
198 	}
199 	else	ndata=data;
200 
201 #if (0)
202 	printf( "Colors1: %d\n", ColorMapSize );
203 	printf( "Colors2: %d\n", gif_p->ColorMapSize );
204 	for (int i=0;i<gif_p->ColorMapSize;i++) {
205 		printf( "%3d: %02x %02x %02x   %02x %02x %02x\n", i,
206 			Red[i], Green[i], Blue[i],
207 			gif_p->Red[i], gif_p->Green[i], gif_p->Blue[i] );
208 	}
209 #endif
210 
211 	int offx = (x21>=0)?x21:0;
212 	int offy = (y21>=0)?y21:0;
213 	for (int y=0;y<gif_p->Height();y++) {
214 		memcpy( ndata+offx+(offy+y)*nwidth, gif_p->data+y*gif_p->Width(), gif_p->Width() );
215 	}
216 
217 	if (ndata!=data) {
218 		free(data);
219 		data   = ndata;
220 		height = nheight;
221 		width  = nwidth;
222 	}
223 }
224 
AddLock(class GifXImage *)225 void GifImage::AddLock(class GifXImage *  /*locker*/ ) {
226 	lockcount++;
227 }
RemoveLock(class GifXImage *)228 void GifImage::RemoveLock(class GifXImage * /*locker*/ ) {
229 	if (!--lockcount) {
230 		delete this;
231 	}
232 }
233 
GetSize(int * w,int * h)234 void GifImage::GetSize( int *w, int *h ) {
235 	*w = Width();
236 	*h = Height();
237 }
238 
GetAverageColor()239 long GifImage::GetAverageColor() {
240 long	erg;
241 int	i;
242 
243 	erg=0;
244 	for (i=Width()*Height();i>0;i--) {
245 		erg+=10*Red[*data];
246 		erg+=5*Green[*data];
247 		erg+=Blue[*data];
248 		data++;
249 	}
250 	return erg;
251 }
252 
253 #define IMAGESEP 0x2c
254 #define EXTENSION 0x21
255 #define INTERLACEMASK 0x40
256 #define COLORMAPMASK 0x80
257 #define ADDTOPIXEL(a) if (Quick) data[Offset++]=a; else AddToPixel(a)
258 
259 #define ALLOCATED 3
260 
261 static int BitOffset,	/* Bit Offset of next code */
262 	XC, YC,					/* Output X and Y coords of current pixel */
263 	Offset,					/* Offset in output array */
264 	Pass,						/* Used by output routine if interlaced pic */
265 	BytesPerScanline,		/* bytes per scanline in output raster */
266 	NumUsed,					/* Number of colors really used */
267 	CodeSize,				/* Code size, read from GIF header */
268 	ReadMask;				/* Code AND mask for current code size */
269 
270 static boolean Interlace;
271 
272 static byte *Raster;		/* The raster data stream, unblocked */
273 
274 	/* The GIF headers found in the file */
275 static byte gifheader[13];
276 static byte imageheader[9];
277 static byte colormap[3*256];
278 
279 	/* The hash table used by the decompressor */
280 static int  Prefix[4096];
281 static int  Suffix[4096];
282 
283 	/* An output array used by the decompressor */
284 static byte OutCode[1025];
285 
286 	/* The color map, read from the GIF header */
287 static byte used[256];
288 
289 static char id[] = "GIF";
290 
291 
292 /*****************************/
LoadGIF(const char * fname)293 int GifImage::LoadGIF(const char *fname)
294 /*****************************/
295 {
296 	register byte ch;
297 	FILE *fp;
298 
299 	BitOffset = 0,				/* Bit Offset of next code */
300 	XC = 0, YC = 0,				/* Output X and Y coords of current pixel */
301 	Offset = 0,				 /* Offset in output array */
302 	Pass = 0;						/* Used by output routine if interlaced pic */
303 	ColorMapSize = 0;
304 	data = NULL;
305 
306 	fp = fopen(fname,"rb");
307 
308 	if (!fp) {
309 			fprintf(stderr,"'%s': File not found\n", fname);
310 			exit(0);
311 	}
312 
313 	if ( (fread(gifheader, sizeof(gifheader), 1, fp)!=1)
314 	  || ( (strncmp((char*)gifheader, id, 3)!=0)
315 	    && (strncmp((char*)gifheader, "FIG", 3)!=0) ) )
316 	  		{		fprintf(stderr,"'%s' not a GIF file\n", fname );
317 	  				return 1;
318 	  		}
319 
320 	if (strncmp((char*)gifheader+3, "87a", 3) && strncmp((char*)gifheader+3,"89a",3))
321 		fprintf(stderr,"Warning: %s contains unknown version %c%c%c",fname,
322 		   gifheader[3],gifheader[4],gifheader[5]);
323 	HasColormap = ((gifheader[10] & COLORMAPMASK) ? True : False);
324 	ColorMapSize = 1 << (gifheader[10]&7)+1;
325 
326 	Background = gifheader[11];				/* background color... not used. */
327 
328 /* Read in global colormap. */
329 	if (HasColormap) ReadColormap(fp);
330 
331 /* Check for image extension */
332 	while ((ch=getc(fp)) == EXTENSION)
333 	{
334 		char	buffer[256];
335 
336 		first=new Extension(getc(fp),first);
337 		while ((ch=getc(fp))>0) {
338 			fread(buffer,ch,1,fp);
339 			first->AddData(buffer,ch);
340 		}
341 	}
342 
343 	if (ch != IMAGESEP) {
344 		fprintf(stderr,"'%s': corrupt GIF file (no image separator) '%x'\n", fname, ch);
345 		return 1;
346 	}
347 
348 	fread(imageheader,sizeof(imageheader),1,fp);
349 
350 	width		= imageheader[4] + 0x100 * imageheader[5];
351 	height	= imageheader[6] + 0x100 * imageheader[7];
352 
353 	if (!quiet || fastinfo_flag) {
354 		printf("%s: %d x %d x %d\n", fname, Width(), Height(), ColorMapSize);
355 		fclose(fp);
356 		return 1;
357 	}
358 
359 	Interlace = ((imageheader[8] & INTERLACEMASK) ? True : False);
360 
361 	if (imageheader[8] & COLORMAPMASK)
362 	{
363 		HasColormap = True;
364 		ColorMapSize = 1 << (imageheader[8]&7)+1;
365 		ReadColormap(fp);
366 	}
367 	CodeSize = getc(fp);
368 	ReadImageData(fp);
369 	fclose(fp);
370 	DecodeImage();
371 	return 0;
372 }
373 
374 
ReadImageData(FILE * fp)375 int GifImage::ReadImageData(FILE *fp)
376 {
377 /* Read the raster data.  Here we just transpose it from the GIF array
378  * to the Raster array, turning it from a series of blocks into one long
379  * data stream, which makes life much easier for ReadCode().
380  */
381 	long filesize, filepos;
382 	int ch;
383 	byte *ptr1;
384 
385 	/* find the size of the file */
386 	filepos = ftell(fp);
387 	fseek(fp, 0L, 2);
388 	filesize = ftell(fp)-filepos;
389 	fseek(fp, filepos, 0);
390 
391 	if (!(Raster = (byte *) malloc((unsigned)filesize))) {
392 			fprintf(stderr,"Not enough memory to store gif data");
393 			exit(-1);
394 	}
395 
396 	ptr1 = Raster;
397 	while ((ch = getc(fp))>0)
398 	{
399 		if (fread(ptr1, 1, ch, fp)<(unsigned)ch)
400 				fprintf(stderr,"corrupt GIF file (unblock)\n");
401 		ptr1 += ch;
402 	}
403 	return 0;
404 }
405 
CropImage(int x1,int y1,int x2,int y2)406 int GifImage::CropImage(int x1,int y1, int x2, int y2) {
407 int	w = x2-x1;
408 int	h = y2-y1;
409 
410 	if (x1<0 || x2>width  || w<0 || y1<0 || y2>height || h<0) {
411 		fprintf(stderr,"unable to crop (%d,%d)-(%d,%d)\n", x1,y1,x2,y2);
412 		fprintf(stderr,"image size: %dx%d\n", width, height );
413 		exit(-1);
414 	}
415 
416 	for (int i=0;i<h;i++) {
417 			memmove(data+i*w,data+(i+y1)*Width()+x1,w);
418 	}
419 	width  = w;
420 	height = h;
421 	return 0;
422 }
423 
CropImage()424 int GifImage::CropImage() {
425 int		i,j;
426 int		b;
427 int		x1,x2,y1,y2;
428 byte		*ptr;
429 long		d;
430 
431 	b=*data;
432 	d=0x7fffffff;
433 	for (i=0;i<256;i++) {
434 			if (Red[i]+Green[i]+Blue[i]<d) {
435 					b=i;
436 					d=Red[i]+Green[i]+Blue[i];
437 			}
438 	}
439 	x1=-1; x2=Width();
440 	y1=-1; y2=Height();
441 	for (i=0; i<Height(); i++) {
442 			int		flag[256];
443 			int		count=0;
444 			ptr = data + (i*Width());
445 			for (j=0;j<256;j++)		flag[j]=0;
446 		for (j=0; j<Width(); j++,ptr++) {
447 				if (!flag[*ptr]) {
448 						flag[*ptr]++;
449 						if (++count>=minpix)		break;
450 				}
451 		}
452 		if (count>=minpix)		break;
453 		y1=i;
454 	}
455 	for (i=Height()-1;i>=0; i--) {
456 			int		flag[256];
457 			int		count=0;
458 			ptr = data + (i*Width());
459 			for (j=0;j<256;j++)		flag[j]=0;
460 		for (j=0; j<Width(); j++,ptr++) {
461 				if (!flag[*ptr]) {
462 						flag[*ptr]++;
463 						if (++count>=minpix)		break;
464 				}
465 		}
466 		if (count>=minpix)		break;
467 		y2=i;
468 	}
469 
470 	for (i=0; i<Width(); i++) {
471 			int		flag[256];
472 			int		count=0;
473 			ptr = data + i;
474 			for (j=0;j<256;j++)		flag[j]=0;
475 		for (j=0; j<Height(); j++,ptr+=Width()) {
476 				if (!flag[*ptr]) {
477 						flag[*ptr]++;
478 						if (++count>=minpix)		break;
479 				}
480 		}
481 		if (count>=minpix)		break;
482 		x1=i;
483 	}
484 	for (i=Width()-1;i>=0;i--) {
485 			int		flag[256];
486 			int		count=0;
487 			ptr = data + i;
488 			for (j=0;j<256;j++)		flag[j]=0;
489 		for (j=0; j<Height(); j++,ptr+=Width()) {
490 				if (!flag[*ptr]) {
491 						flag[*ptr]++;
492 						if (++count>=minpix)		break;
493 				}
494 		}
495 		if (count>=minpix)		break;
496 		x2=i;
497 	}
498 
499 	x1++; x2--; y1++; y2--;
500 	if (x2<=x1||y2<=y1)				return 1;
501 
502 	CropImage(x1,y1,x2,y2);
503 	return 0;
504 }
505 
DecodeImage()506 int  GifImage::DecodeImage()
507 {
508 /* Start reading the raster data. First we get the intial code size
509  * and compute decompressor constant values, based on this code size.
510  */
511 int Quick,						/* True, when not interlaced and local Cmap */
512 	InitCodeSize,				/* Starting code size, used during Clear */
513 	InCode,						/* Value returned by ReadCode */
514 	MaxCode,						/* limiting value for current code size */
515 	ClearCode,					/* GIF clear code */
516 	EOFCode,						/* GIF end-of-information code */
517 	CurCode, OldCode = 0,	/* Decompressor variables */
518 	FreeCode,					/* Decompressor, next free slot in hashtable */
519 	OutCount = 0,				/* Decompressor output 'stack count' */
520 	FinChar = 0,				/* Decompressor variable */
521 	BitMask;						/* AND mask for data size */
522 
523 	BitMask = ColorMapSize - 1;
524 
525 	ClearCode = (1 << CodeSize);
526 	EOFCode = ClearCode + 1;
527 	FreeCode = ClearCode + 2;
528 
529 /* The GIF spec has it that the code size is the code size used to
530  * compute the above values is the code size given in the file, but the
531  * code size used in compression/decompression is the code size given in
532  * the file plus one. (thus the ++).
533  */
534 
535 	CodeSize++;
536 	InitCodeSize = CodeSize;
537 	MaxCode = (1 << CodeSize);
538 	ReadMask = MaxCode - 1;
539 
540 /* Allocate the X Image */
541 	if (!(data = (byte *) malloc(Width()*Height()))) {
542 		fprintf(stderr,"not enough memory for image");
543 		exit(-1);
544 	}
545 
546 #if (0)
547 	if (!(theImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0, (char*)Image,
548 							 Width(), Height(), 8, Width()))) {
549 		fprintf(stderr,"unable to create XImage");
550 		return -1;
551 	}
552 #endif
553 
554 	BytesPerScanline = Width();
555 
556 /* Decompress the file, continuing until you see the GIF EOF code.
557  * One obvious enhancement is to add checking for corrupt files here.
558  */
559 	Quick = !Interlace;
560 	Offset = 0;
561 	if (DEBUG) fprintf(stderr,"Decoding...\n");
562 	InCode = ReadCode();
563 	while (InCode != EOFCode) {
564 
565 /* Clear code sets everything back to its initial value, then reads the
566  * immediately subsequent code as uncompressed data.
567  */
568 
569 		if (InCode == ClearCode) {
570 			CodeSize = InitCodeSize;
571 			MaxCode = (1 << CodeSize);
572 			ReadMask = MaxCode - 1;
573 			FreeCode = ClearCode + 2;
574 			CurCode = OldCode = InCode = ReadCode();
575 			FinChar = CurCode & BitMask;
576 			ADDTOPIXEL(FinChar);
577 		}
578 		else {
579 
580 /* If not a clear code, then must be data: save same as CurCode */
581 
582 			CurCode = InCode;
583 
584 /* If greater or equal to FreeCode, not in the hash table yet;
585  * repeat the last character decoded
586  */
587 
588 			if (CurCode >= FreeCode) {
589 				CurCode = OldCode;
590 				OutCode[OutCount++] = FinChar;
591 			}
592 
593 /* Unless this code is raw data, pursue the chain pointed to by CurCode
594  * through the hash table to its end; each code in the chain puts its
595  * associated output code on the output queue.
596  */
597 
598 			while (CurCode > BitMask) {
599 				if (OutCount >= 1024) {
600 					fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n");
601 					exit(1);
602 				}
603 				OutCode[OutCount++] = Suffix[CurCode];
604 				CurCode = Prefix[CurCode];
605 			}
606 
607 /* The last code in the chain is treated as raw data. */
608 
609 			/* OutCode[OutCount++] = FinChar = CurCode &BitMask*/;
610 			FinChar = CurCode & BitMask;
611 			ADDTOPIXEL(FinChar);
612 
613 /* Now we put the data out to the Output routine.
614  * It's been stacked LIFO, so deal with it that way...  */
615 			while (OutCount>0)
616 				ADDTOPIXEL(OutCode[--OutCount]);
617 
618 /* Build the hash table on-the-fly. No table is stored in the file. */
619 
620 			Prefix[FreeCode] = OldCode;
621 			Suffix[FreeCode] = FinChar;
622 			OldCode = InCode;
623 
624 /* Point to the next slot in the table.  If we exceed the current
625  * MaxCode value, increment the code size unless it's already 12.  If it
626  * is, do nothing: the next code decompressed better be CLEAR
627  */
628 
629 			FreeCode++;
630 			if (FreeCode >= MaxCode) {
631 				if (CodeSize < 12) {
632 					CodeSize++;
633 					MaxCode *= 2;
634 					ReadMask = (1 << CodeSize) - 1;
635 				}
636 			}
637 		}
638 		InCode = ReadCode();
639 	}
640 	free(Raster);
641 	return 0;
642 }
643 
644 
645 /* Fetch the next code from the raster data stream.  The codes can be
646  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
647  * maintain our location in the Raster array as a BIT Offset.  We compute
648  * the byte Offset into the raster array by dividing this by 8, pick up
649  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
650  * bring the desired code to the bottom, then mask it off and return it.
651  */
ReadCode()652 int GifImage::ReadCode()
653 {
654 	int RawCode, ByteOffset, BitShift;
655 
656 	ByteOffset = BitOffset / 8;
657 	BitShift = BitOffset % 8;
658 	BitOffset += CodeSize;
659 	if (BitShift+CodeSize<8)
660 		return (Raster[ByteOffset]>>BitShift) & ReadMask;
661 	else
662 	{
663 		RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
664 		if (BitShift+CodeSize >= 16)
665 			RawCode += (0x10000 * Raster[ByteOffset + 2]);
666 		return((RawCode>>BitShift) & ReadMask);
667 	}
668 }
669 
670 
AddToPixel(byte Index)671 void GifImage::AddToPixel(byte Index)
672 {
673 	if (YC<Height()) /* Might be of importance when reading interlaced gifs */
674 		data[YC*BytesPerScanline+XC] = Index;
675 	if (!used[Index]) { used[Index]=True; NumUsed++; }
676 	if (++XC == Width())
677 	{
678 		XC = 0;
679 		if (Interlace)
680 		{
681 			switch (Pass)
682 			{
683 			case 0: YC += 8; if (YC >= Height()) { Pass++; YC = 4; } break;
684 			case 1: YC += 8; if (YC >= Height()) { Pass++; YC = 2; } break;
685 			case 2: YC += 4; if (YC >= Height()) { Pass++; YC = 1; } break;
686 			case 3: YC += 2; break;
687 			default: break;
688 			}
689 		}
690 		else
691 			YC++;
692 	}
693 }
694 
695 
696 
ReadColormap(FILE * fp)697 void GifImage::ReadColormap(FILE *fp)
698 {
699 	byte *ptr=colormap;
700 	int i;
701 
702 	if (DEBUG) fprintf(stderr,"Reading Color map...\n");
703 	fread(colormap, ColorMapSize, 3, fp);
704 	for (i = 0; i < ColorMapSize; i++) {
705 		Red[i] = (*ptr++);
706 		Green[i] = (*ptr++);
707 		Blue[i] = (*ptr++);
708 		used[i] = 0;
709 	}
710 	NumUsed=0;
711 }
712 
713 
CloseGif()714 void GifImage::CloseGif()
715 {
716 #if (0)
717 	if (LocalCmap)
718 	{
719 		XFreeColormap(theDisp, LocalCmap);
720 		LocalCmap=0;
721 	}
722 	else
723 	{
724 		int i,j;
725 		unsigned long pixels[256];
726 
727 		for (j=i=0;i<ColorMapSize;i++)
728 			if (used[i]==ALLOCATED)
729 				pixels[j++]=cols[i];
730 		XFreeColors(theDisp, theCmap, pixels, j, 0L);
731 	}
732 #endif
733 	if (data)
734 	{
735 		free(data);
736 		data=NULL;
737 	}
738 }
739 
740