1 /******************************************************************************
2 * "Gif-Lib" - Yet another gif library. *
3 * *
4 * Written by: Gershon Elber IBM PC Ver 1.1, Aug. 1990 *
5 *******************************************************************************
6 * The kernel of the GIF Decoding process can be found here. *
7 *******************************************************************************
8 * History: *
9 * 16 Jun 89 - Version 1.0 by Gershon Elber. *
10 * 3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
11 ******************************************************************************/
12
13 # include <stdio.h>
14 # include <stdlib.h>
15 # include <string.h>
16 # include "bm_gif_lib.h"
17
18 # include <sioBlocked.h>
19 # include <sioLzw.h>
20 # include <sioEndian.h>
21 # include <appDebugon.h>
22
23 /************************************************************************/
24 /* */
25 /* Read a palette from the input file. */
26 /* */
27 /************************************************************************/
28
bmGifInitGifColorMap(GifColorMap * gcm)29 void bmGifInitGifColorMap( GifColorMap * gcm )
30 {
31 int i;
32 RGB8Color * rgb8;
33
34 gcm->gcmColorCount= 0;
35 gcm->gcmBitsPerPixel= 0;
36
37 rgb8= gcm->gcmColors;
38 for ( i = 0; i < 256; rgb8++, i++ )
39 {
40 rgb8->rgb8Red= 255;
41 rgb8->rgb8Green= 255;
42 rgb8->rgb8Blue= 255;
43 rgb8->rgb8Alpha= 255;
44 }
45
46 return;
47 }
48
bmGifReadColorMap(GifFileType * gft,GifColorMap * gcm,int bitsPerPixel)49 static int bmGifReadColorMap( GifFileType * gft,
50 GifColorMap * gcm,
51 int bitsPerPixel )
52 {
53 RGB8Color * rgb8;
54 int i;
55
56 bmGifInitGifColorMap( gcm );
57
58 gcm->gcmBitsPerPixel= bitsPerPixel;
59 gcm->gcmColorCount= 1 << bitsPerPixel;
60
61 rgb8= gcm->gcmColors;
62 for ( i = 0; i < gcm->gcmColorCount; rgb8++, i++ )
63 {
64 rgb8->rgb8Red= sioInGetByte( gft->gftSis );
65 rgb8->rgb8Green= sioInGetByte( gft->gftSis );
66 rgb8->rgb8Blue= sioInGetByte( gft->gftSis );
67 }
68
69 return 0;
70 }
71
72 /************************************************************************/
73 /* */
74 /* Read the screen descriptor from the input file. */
75 /* This is the first information that is read from the file by the */
76 /* open routine. */
77 /* */
78 /* 1) Opened for reading? */
79 /* 2) Read screen size. */
80 /* 3) Read the description of the global color map. */
81 /* 4) And interpret it. */
82 /* 5) Read global palette (if any). */
83 /* */
84 /************************************************************************/
85
bmGifReadScreenDescriptor(GifFileType * gft)86 static int bmGifReadScreenDescriptor( GifFileType * gft )
87 {
88 GifScreenDescriptor * gsd= &(gft->gftScreenDescriptor);
89
90 int bitsPerPixel;
91
92 /* 1 */
93 if ( ! gft->gftSis )
94 {
95 XDEB(gft->gftSis);
96 _GifError= D_GIF_ERR_NOT_READABLE;
97 return GIF_ERROR;
98 }
99
100 bmGifInitGifColorMap( &(gsd->gsdScreenColorMap) );
101
102 /* 2 */
103 gsd->gsdScreenWide= sioEndianGetLeInt16( gft->gftSis );
104 gsd->gsdScreenHigh= sioEndianGetLeInt16( gft->gftSis );
105
106 /* 3 */
107 gsd->gsdPackedFields= sioInGetByte( gft->gftSis );
108 gsd->gsdScreenBackgroundColor= sioInGetByte( gft->gftSis );
109 gsd->gsdScreenAspectRatio= sioInGetByte( gft->gftSis );
110
111 /* 4 */
112 gsd->gsdScreenBitsPerPixel = (((gsd->gsdPackedFields & 0x70) + 1) >> 4) + 1;
113 bitsPerPixel= ( gsd->gsdPackedFields & 0x07 ) + 1;
114
115 /* 5 */
116 if ( gsd->gsdPackedFields & 0x80 )
117 {
118 if ( bmGifReadColorMap( gft,
119 &(gsd->gsdScreenColorMap), bitsPerPixel ) )
120 { LDEB(bitsPerPixel); return GIF_ERROR; }
121 }
122
123 return GIF_OK;
124 }
125
126 /************************************************************************/
127 /* */
128 /* Setup the LZ decompression for this image */
129 /* */
130 /* 3) Open the blocked input stream. (Push it on the unstructured */
131 /* one.) */
132 /* 4) Open the LZW stream (Push it on the blocked one.) */
133 /* */
134 /************************************************************************/
135
DGifSetupDecompress(GifFileType * gft)136 static int DGifSetupDecompress( GifFileType * gft )
137 {
138 int codeSize;
139
140 codeSize= sioInGetByte( gft->gftSis );
141 if ( codeSize == EOF )
142 { LDEB(codeSize); return GIF_ERROR; }
143
144 /* 3 */
145 if ( gft->gftSisBlocked )
146 { XDEB(gft->gftSisBlocked); }
147
148 gft->gftSisBlocked= sioInBlockedOpen( gft->gftSis );
149 if ( ! gft->gftSisBlocked )
150 { XDEB(gft->gftSisBlocked); return GIF_ERROR; }
151
152 /* 4 */
153 if ( gft->gftSisLzw )
154 { XDEB(gft->gftSisLzw); }
155
156 gft->gftSisLzw= sioInLzwGifOpen( gft->gftSisBlocked, codeSize );
157 if ( ! gft->gftSisLzw )
158 { XDEB(gft->gftSisLzw); return GIF_ERROR; }
159
160 return GIF_OK;
161 }
162
bmGifCleanupDecompress(GifFileType * gft)163 static void bmGifCleanupDecompress( GifFileType * gft )
164 {
165 if ( gft->gftSisLzw )
166 {
167 if ( sioInClose( gft->gftSisLzw ) )
168 { XDEB(gft->gftSisLzw); }
169
170 gft->gftSisLzw= (SimpleInputStream *)0;
171 }
172
173 if ( gft->gftSisBlocked )
174 {
175 if ( sioInClose( gft->gftSisBlocked ) )
176 { XDEB(gft->gftSisBlocked); }
177
178 gft->gftSisBlocked= (SimpleInputStream *)0;
179 }
180
181 return;
182 }
183
184 /******************************************************************************
185 * Update a new gif file, given its file handle. *
186 * Returns GifFileType pointer dynamically allocated which serves as the gif *
187 * info record. _GifError is cleared if succesfull. *
188 ******************************************************************************/
189
DGifOpenFileHandle(SimpleInputStream * sis)190 GifFileType *DGifOpenFileHandle( SimpleInputStream * sis )
191 {
192 GifFileType * gft;
193
194 gft= (GifFileType *)malloc( sizeof(GifFileType) );
195 if ( ! gft )
196 { XDEB(gft); return (GifFileType *)0; }
197
198 memset( gft, '\0', sizeof(GifFileType));
199
200 strncpy( gft->gftVersionString, GIF87_STAMP, 6 )[6]= '\0';
201
202 gft->gftSis= sis;
203 gft->gftSisBlocked= (SimpleInputStream *)0;
204 gft->gftSisLzw= (SimpleInputStream *)0;
205
206 /* Lets see if this is a GIF file: */
207 if ( sioInReadBytes( gft->gftSis,
208 (unsigned char *)gft->gftVersionString, 6 ) != 6 )
209 {
210 LDEB(6);
211 _GifError= D_GIF_ERR_READ_FAILED;
212 free( gft );
213 return (GifFileType *)0;
214 }
215
216 if ( strcmp( gft->gftVersionString, GIF87_STAMP ) &&
217 strcmp( gft->gftVersionString, GIF89_STAMP ) )
218 {
219 SDEB(gft->gftVersionString);
220 _GifError= D_GIF_ERR_NOT_GIF_FILE;
221 free( gft );
222 return (GifFileType *)0;
223 }
224
225 if ( bmGifReadScreenDescriptor( gft ) == GIF_ERROR )
226 {
227 LDEB(1);
228 free( gft );
229 return (GifFileType *)0;
230 }
231
232 _GifError = 0;
233
234 return gft;
235 }
236
237 /******************************************************************************
238 * This routine should be called before any attemp to read an image. *
239 ******************************************************************************/
240
bmGifGetRecordType(GifFileType * gft,GifRecordType * Type)241 int bmGifGetRecordType(GifFileType *gft, GifRecordType *Type)
242 {
243 unsigned char c;
244
245 /* 1 */
246 if ( ! gft->gftSis )
247 {
248 XDEB(gft->gftSis);
249 _GifError= D_GIF_ERR_NOT_READABLE;
250 return GIF_ERROR;
251 }
252
253 c= sioInGetByte( gft->gftSis );
254
255 switch( c )
256 {
257 case ',':
258 *Type= IMAGE_DESC_RECORD_TYPE;
259 break;
260
261 case '!':
262 *Type= EXTENSION_RECORD_TYPE;
263 break;
264
265 case ';':
266 *Type= TERMINATE_RECORD_TYPE;
267 break;
268
269 default:
270 CDEB(c);
271 *Type= UNDEFINED_RECORD_TYPE;
272 _GifError = D_GIF_ERR_WRONG_RECORD;
273 return GIF_ERROR;
274 }
275
276 return GIF_OK;
277 }
278
279 /************************************************************************/
280 /* */
281 /* Read an image descriptor from the input file. */
282 /* NOTE that it is assumed the Image desc. header (',') has been read. */
283 /* */
284 /* 1) Opened for reading? */
285 /* 2) Read image geometry. */
286 /* 3) Get image flag bits. */
287 /* 4) Does the image have its own palette.. If so read it. */
288 /* */
289 /************************************************************************/
290
DGifGetImageDesc(GifFileType * gft)291 int DGifGetImageDesc( GifFileType * gft )
292 {
293 int bitsPerPixel;
294 GifByteType Buf[3];
295 GifImageDesc * gid= &(gft->gftCurrentImageDescriptor);
296
297 /* 1 */
298 if ( ! gft->gftSis )
299 {
300 XDEB(gft->gftSis);
301 _GifError= D_GIF_ERR_NOT_READABLE;
302 return GIF_ERROR;
303 }
304
305 /* 2 */
306 gid->Left= sioEndianGetLeInt16( gft->gftSis );
307 gid->Top= sioEndianGetLeInt16( gft->gftSis );
308 gid->Width= sioEndianGetLeInt16( gft->gftSis );
309 gid->Height= sioEndianGetLeInt16( gft->gftSis );
310
311 /* 3 */
312 Buf[0]= sioInGetByte( gft->gftSis );
313
314 bitsPerPixel= (Buf[0] & 0x07) + 1;
315 gid->Interlace= (Buf[0] & 0x40);
316
317 bmGifInitGifColorMap( &(gid->gidImageColorMap) );
318
319 /* 4 */
320 if ( Buf[0] & 0x80 )
321 {
322 if ( bmGifReadColorMap( gft, &(gid->gidImageColorMap),
323 bitsPerPixel ) )
324 { LDEB(bitsPerPixel); return GIF_ERROR; }
325 }
326
327 gft->gftPixelCount= (long)gid->Width *(long)gid->Height;
328
329 DGifSetupDecompress( gft ); /* Reset decompress algorithm parameters. */
330
331 return GIF_OK;
332 }
333
334 /************************************************************************/
335 /* */
336 /* Get one full scanned line (buffer) of length count from GIF file. */
337 /* */
338 /* 3) The image is finished.. Close (and drain) to blocked input */
339 /* stream. */
340 /* */
341 /************************************************************************/
342
bmGifGetPixels(GifFileType * gft,int * pFoundTransparent,unsigned char * buffer,int count,int transparentColor)343 int bmGifGetPixels( GifFileType * gft,
344 int * pFoundTransparent,
345 unsigned char * buffer,
346 int count,
347 int transparentColor )
348 {
349 if ( ! gft->gftSis )
350 {
351 XDEB(gft->gftSis);
352 _GifError= D_GIF_ERR_NOT_READABLE;
353 return GIF_ERROR;
354 }
355
356 if ( count > gft->gftPixelCount )
357 {
358 LLDEB(count,gft->gftPixelCount);
359 _GifError = D_GIF_ERR_DATA_TOO_BIG;
360 return GIF_ERROR;
361 }
362
363 gft->gftPixelCount -= count;
364
365 if ( sioInReadBytes( gft->gftSisLzw, buffer, count ) == count )
366 {
367 if ( transparentColor >= 0 && ! *pFoundTransparent )
368 {
369 int i;
370
371 for ( i= 0; i < count; i++ )
372 {
373 if ( buffer[i] == transparentColor )
374 { *pFoundTransparent= 1; }
375 }
376 }
377
378 if ( gft->gftPixelCount == 0 )
379 { bmGifCleanupDecompress( gft ); }
380
381 return GIF_OK;
382 }
383 else{ LDEB(count); return GIF_ERROR; }
384 }
385
386 /************************************************************************/
387 /* */
388 /* Get an extension block (see GIF manual) from gif file. This */
389 /* routine only returns the first data block, and */
390 /* DGifGetExtensionNext shouldbe called after this one until NULL */
391 /* extension is returned. */
392 /* The Extension should NOT be freed by the user (not dynamically */
393 /* allocated). */
394 /* Note it is assumed the Extension desc. header ('!') has been read. */
395 /* */
396 /************************************************************************/
397
DGifGetExtension(GifFileType * gft,int * ExtCode,GifByteType Extension[256])398 int DGifGetExtension( GifFileType * gft,
399 int * ExtCode,
400 GifByteType Extension[256] )
401 {
402 GifByteType Buf;
403 int got;
404
405 if ( ! gft->gftSis )
406 {
407 XDEB(gft->gftSis);
408 _GifError= D_GIF_ERR_NOT_READABLE;
409 return GIF_ERROR;
410 }
411
412 Buf= sioInGetByte( gft->gftSis );
413
414 *ExtCode= Buf;
415
416 if ( DGifGetExtensionNext( gft, &got, Extension) != GIF_OK )
417 { LDEB(1); return GIF_ERROR; }
418 if ( ! got )
419 { LDEB(got); return GIF_ERROR; }
420
421 return GIF_OK;
422 }
423
424 /************************************************************************/
425 /* */
426 /* Get a following extension block (see GIF manual) from gif file. */
427 /* This routine should be called until NULL Extension is returned. */
428 /* The Extension should NOT be freed by the user (not dynamically */
429 /* allocated). */
430 /* */
431 /************************************************************************/
432
DGifGetExtensionNext(GifFileType * gft,int * pGot,GifByteType Extension[256])433 int DGifGetExtensionNext( GifFileType * gft,
434 int * pGot,
435 GifByteType Extension[256] )
436 {
437 int byte;
438
439 byte= sioInGetByte( gft->gftSis );
440 if ( byte == EOF )
441 {
442 XDEB(byte);
443 _GifError = D_GIF_ERR_READ_FAILED;
444 return GIF_ERROR;
445 }
446
447 if ( byte == 0 )
448 { *pGot= 0; return GIF_OK; }
449
450 if ( sioInReadBytes( gft->gftSis, Extension+ 1, byte ) != byte )
451 {
452 LDEB(byte);
453 _GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR;
454 }
455 *pGot= 1;
456 Extension[0]= byte;
457 return GIF_OK;
458 }
459
460 /************************************************************************/
461 /* */
462 /* Close a gif file that was opened for reading: Do the necessary */
463 /* cleanup. */
464 /* */
465 /************************************************************************/
466
DGifCloseFile(GifFileType * gft)467 int DGifCloseFile(GifFileType *gft)
468 {
469 if (gft == NULL) return GIF_ERROR;
470
471 if ( ! gft->gftSis )
472 {
473 XDEB(gft->gftSis);
474 _GifError= D_GIF_ERR_NOT_READABLE;
475 return GIF_ERROR;
476 }
477
478 bmGifCleanupDecompress( gft );
479
480 free(gft);
481
482 return GIF_OK;
483 }
484
485