1 #   include	"bitmapConfig.h"
2 
3 #   include	<stdlib.h>
4 #   include	<stdio.h>
5 
6 #   include	<sioFileio.h>
7 
8 #   include	"bmintern.h"
9 #   include	"bmio.h"
10 #   include	<appDebugon.h>
11 
12 #   include	"bm_gif_lib.h"
13 
14 int _GifError = 0;
15 
16 /************************************************************************/
17 /*									*/
18 /*  Read a GIF file.							*/
19 /*									*/
20 /************************************************************************/
21 
22 
bmGifReadImageBuffer(BitmapDescription * bd,GifFileType * gft,unsigned char * buffer,int tc,int interlaced)23 static int bmGifReadImageBuffer(BitmapDescription *	bd,
24 				GifFileType *		gft,
25 				unsigned char *		buffer,
26 				int			tc,
27 				int			interlaced )
28     {
29     int			row;
30 
31     int			wide= bd->bdPixelsWide;
32     int			bpr= bd->bdBytesPerRow;
33 
34     int			ft= 0;
35     int			cc;
36 
37     if  ( interlaced )
38 	{
39 	for ( row= 0; row < bd->bdPixelsHigh; row += 8 )
40 	    {
41 	    if  ( bmGifGetPixels( gft, &ft, buffer+ row* bpr, wide, tc ) !=
42 								    GIF_OK )
43 		{ LDEB(row); return -1; }
44 	    }
45 	for ( row= 4; row < bd->bdPixelsHigh; row += 8 )
46 	    {
47 	    if  ( bmGifGetPixels( gft, &ft, buffer+ row* bpr, wide, tc ) !=
48 								    GIF_OK )
49 		{ LDEB(row); return -1; }
50 	    }
51 	for ( row= 2; row < bd->bdPixelsHigh; row += 4 )
52 	    {
53 	    if  ( bmGifGetPixels( gft, &ft, buffer+ row* bpr, wide, tc ) !=
54 								    GIF_OK )
55 		{ LDEB(row); return -1; }
56 	    }
57 	for ( row= 1; row < bd->bdPixelsHigh; row += 2 )
58 	    {
59 	    if  ( bmGifGetPixels( gft, &ft, buffer+ row* bpr, wide, tc ) !=
60 								    GIF_OK )
61 		{ LDEB(row); return -1; }
62 	    }
63 	}
64     else{
65 	for ( row= 0; row < bd->bdPixelsHigh; row++ )
66 	    {
67 	    if  ( bmGifGetPixels( gft, &ft, buffer+ row* bpr, wide, tc ) !=
68 								    GIF_OK )
69 		{ LDEB(row); return -1; }
70 	    }
71 	}
72 
73     if  ( ! ft )
74 	{ bd->bdHasAlpha= 0;	}
75 
76     cc= 0;
77     if  ( bd->bdHasAlpha )
78 	{
79 	for ( row= 0; row < bd->bdPixelsHigh; row++ )
80 	    {
81 	    unsigned char *	to=   buffer+ row* bpr+ bpr-  1;
82 	    unsigned char *	from= buffer+ row* bpr+ wide- 1;
83 	    int		col;
84 
85 	    for ( col= 0; col < bd->bdPixelsWide; col++ )
86 		{
87 		if  ( *from == tc )
88 		    { *(to--)= 0x00; }
89 		else{ *(to--)= 0xff; }
90 
91 		if  ( *from >= cc )
92 		    { cc= *from+ 1;	}
93 
94 		*(to--)= *(from--);
95 		}
96 	    }
97 	}
98     else{
99 	for ( row= 0; row < bd->bdPixelsHigh; row++ )
100 	    {
101 	    unsigned char *	from= buffer+ row* bpr+ bpr-  1;
102 	    int		col;
103 
104 	    for ( col= 0; col < bd->bdPixelsWide; col++ )
105 		{
106 		if  ( *from >= cc )
107 		    { cc= *from+ 1;	}
108 
109 		from--;
110 		}
111 	    }
112 	}
113 
114     bd->bdPalette.cpColorCount= cc;
115 
116     return 0;
117     }
118 
bmGifReadGif(BitmapDescription * bd,unsigned char ** pBuffer,SimpleInputStream * sis)119 int bmGifReadGif(		BitmapDescription *	bd,
120 				unsigned char **	pBuffer,
121 				SimpleInputStream *	sis )
122     {
123     int			rval= 0;
124 
125     GifFileType *	gft= (GifFileType *)0;
126     GifImageDesc *	gid;
127     int			transparentColor= -1;
128     int			gotImage= 0;
129 
130     unsigned char *	buffer= (unsigned char *)0;
131 
132     gft= DGifOpenFileHandle( sis );
133     if  ( ! gft )
134 	{ XDEB(gft); rval= -1; goto ready;	}
135 
136     gid= &(gft->gftCurrentImageDescriptor);
137 
138     for (;;)
139 	{
140 	GifRecordType		grt;
141 	unsigned int		row;
142 
143 	GifColorMap *		gcm;
144 	const RGB8Color *	rgb8From;
145 	RGB8Color *		rgb8To;
146 
147 	if  ( bmGifGetRecordType( gft, &grt ) != GIF_OK )
148 	    { LDEB(1); rval= -1; goto ready;	}
149 
150 	switch( grt )
151 	    {
152 	    case UNDEFINED_RECORD_TYPE:
153 		LDEB(grt); continue;
154 
155 	    case SCREEN_DESC_RECORD_TYPE:
156 		LDEB(grt); continue;
157 
158 	    case IMAGE_DESC_RECORD_TYPE:
159 		if  ( gotImage )
160 		    { LDEB(gotImage); break;	}
161 		gotImage= 1;
162 
163 		if  ( DGifGetImageDesc( gft ) != GIF_OK )
164 		    { LDEB(1); rval= -1; goto ready; }
165 		bd->bdPixelsWide= gid->Width;
166 		bd->bdPixelsHigh= gid->Height;
167 		if  ( transparentColor >= 0 )
168 		    { bd->bdHasAlpha= 1;	}
169 		else{ bd->bdHasAlpha= 0;	}
170 		bd->bdUnit= BMunINCH;
171 		bd->bdXResolution= 72;
172 		bd->bdYResolution= 72;
173 
174 		bd->bdBitsPerSample= 8;
175 		if  ( bd->bdHasAlpha )
176 		    { bd->bdBitsPerPixel= 16;	}
177 		else{ bd->bdBitsPerPixel= 8;	}
178 		bd->bdColorEncoding= BMcoRGB8PALETTE;
179 		if  ( utilPaletteSetCount( &(bd->bdPalette), 256 ) )
180 		    { LDEB(256); rval= -1; goto ready;	}
181 
182 		if  ( bmCalculateSizes( bd ) )
183 		    { LDEB(1); rval= -1; goto ready;	}
184 
185 		buffer= (unsigned char *)malloc( bd->bdBufferLength );
186 		if  ( ! buffer )
187 		    { LLDEB(bd->bdBufferLength,buffer); rval= -1; goto ready; }
188 
189 		if  ( gid->gidImageColorMap.gcmColorCount > 0 )
190 		    { gcm= &(gid->gidImageColorMap);		  }
191 		else{ gcm= &(gft->gftScreenDescriptor.gsdScreenColorMap); }
192 
193 		bd->bdPalette.cpColorCount= gcm->gcmColorCount;
194 
195 		rgb8From= gcm->gcmColors;
196 		rgb8To= bd->bdPalette.cpColors;
197 		for ( row= 0; row < bd->bdPalette.cpColorCount;
198 					    rgb8From++, rgb8To++, row++ )
199 		    {
200 		    rgb8To->rgb8Red= rgb8From->rgb8Red;
201 		    rgb8To->rgb8Green= rgb8From->rgb8Green;
202 		    rgb8To->rgb8Blue= rgb8From->rgb8Blue;
203 		    rgb8To->rgb8Alpha= 255* ( row != transparentColor );
204 		    }
205 
206 		if  ( bmGifReadImageBuffer( bd, gft, buffer,
207 					transparentColor, gid->Interlace ) )
208 		    { LDEB(1); rval= -1; goto ready;	}
209 
210 		continue;
211 
212 	    case EXTENSION_RECORD_TYPE:
213 		{
214 		int		extensionType;
215 		unsigned char	extension[256];
216 		int		got= 1;
217 
218 		if  ( DGifGetExtension( gft, &extensionType, extension )
219 								    != GIF_OK )
220 		    { LDEB(1); rval= -1; goto ready; }
221 
222 		switch( extensionType )
223 		    {
224 		    case GRAPHICS_EXT_FUNC_CODE:
225 			if  ( extension[1] & 0x1 )
226 			    { transparentColor= extension[4];	}
227 			break;
228 
229 		    case COMMENT_EXT_FUNC_CODE:
230 			XDEB(extensionType);
231 			appDebug( "Comment=\"%.*s\"\n",
232 						extension[0], extension+ 1 );
233 			break;
234 
235 		    case PLAINTEXT_EXT_FUNC_CODE:
236 			XDEB(extensionType); break;
237 
238 		    case APPLICATION_EXT_FUNC_CODE:
239 			XDEB(extensionType);
240 			appDebug( "Application=\"%.8s\"\n", extension+ 1 );
241 			break;
242 
243 		    default:
244 			XDEB(extensionType); break;
245 		    }
246 
247 		while( got )
248 		    {
249 		    if  ( DGifGetExtensionNext( gft, &got, extension )
250 								!= GIF_OK )
251 			{ LDEB(1); rval= -1; goto ready; }
252 		    }
253 		}
254 		continue;
255 	    case TERMINATE_RECORD_TYPE:
256 		break;
257 	    }
258 
259 	break;
260 	}
261 
262     /* Try to make monochrome */
263     if  ( ! bd->bdHasAlpha )
264 	{ bmMakeMonochrome( bd, buffer );	}
265 
266     /*
267     *pPrivateFormat= privateFormat;
268     */
269     *pBuffer= buffer; buffer= (unsigned char *)0;
270 
271   ready:
272 
273     if  ( gft )
274 	{ DGifCloseFile( gft );	}
275     if  ( buffer )
276 	{ free( buffer );	}
277 
278     return rval;
279     }
280 
bmReadGifFile(const MemoryBuffer * filename,unsigned char ** pBuffer,BitmapDescription * bd,int * pPrivateFormat)281 int bmReadGifFile(	const MemoryBuffer *	filename,
282 			unsigned char **	pBuffer,
283 			BitmapDescription *	bd,
284 			int *			pPrivateFormat )
285     {
286     SimpleInputStream *	sis;
287 
288     sis= sioInFileioOpen( filename );
289     if  ( ! sis )
290 	{ XDEB(sis); return -1;	}
291 
292     if  ( bmGifReadGif( bd, pBuffer, sis ) )
293 	{ LDEB(1); sioInClose( sis ); return -1;	}
294 
295     *pPrivateFormat= 87;
296 
297     sioInClose( sis );
298     return 0;
299     }
300 
301 /************************************************************************/
302 /*									*/
303 /*  Write a GIF file.							*/
304 /*									*/
305 /************************************************************************/
306 
bmGifWriteGif(const BitmapDescription * bd,const unsigned char * buffer,SimpleOutputStream * sos)307 int bmGifWriteGif(		const BitmapDescription *	bd,
308 				const unsigned char *		buffer,
309 				SimpleOutputStream *		sos )
310     {
311     GifFileType *		gft;
312 
313     GifColorMap			gcm;
314 
315     const int			left= 0;
316     const int			top= 0;
317     const int			interlace= 0;
318 
319     unsigned int		row;
320     const unsigned char *	from;
321 
322     int				bpcolor;
323 
324     int				transparentColor= -1;
325     int				backgroundColor= 0;
326 
327     gft= EGifOpenFileHandle( sos );
328     if  ( ! gft )
329 	{ XDEB(gft); return -1;	}
330 
331     bmGifInitGifColorMap( &gcm );
332 
333     /*  1  */
334     switch( bd->bdColorEncoding )
335 	{
336 	case BMcoWHITEBLACK:
337 	case BMcoBLACKWHITE:
338 	    if  ( bmMakeGrayPalette( bd, &(gcm.gcmColorCount),
339 				    &transparentColor, gcm.gcmColors, 256 ) )
340 		{ LDEB(bd->bdBitsPerPixel); return -1;	}
341 
342 	    gcm.gcmBitsPerPixel= bd->bdBitsPerPixel;
343 
344 	    break;
345 
346 	case BMcoRGB8PALETTE:
347 	    bpcolor= 1;
348 	    while( ( 1 << bpcolor ) < bd->bdPalette.cpColorCount )
349 		{ bpcolor++;	}
350 
351 	    if  ( bpcolor > 8 )
352 		{
353 		LDEB(bpcolor);
354 		LLDEB(bd->bdColorEncoding,bd->bdBitsPerPixel);
355 		return -1;
356 		}
357 
358 	    gcm.gcmBitsPerPixel= bpcolor;
359 	    gcm.gcmColorCount= 1 << gcm.gcmBitsPerPixel;
360 
361 	    for ( row= 0; row < bd->bdPalette.cpColorCount; row++ )
362 		{
363 		gcm.gcmColors[row]= bd->bdPalette.cpColors[row];
364 
365 		if  ( transparentColor < 0				&&
366 		      bd->bdPalette.cpColors[row].rgb8Alpha == 0	)
367 		    { transparentColor= backgroundColor= row;	}
368 		}
369 
370 	    if  ( bd->bdHasAlpha && transparentColor < 0 )
371 		{
372 		transparentColor= bd->bdPalette.cpColorCount;
373 
374 		if  ( gcm.gcmBitsPerPixel < 8			&&
375 		      transparentColor >= gcm.gcmColorCount	)
376 		    {
377 		    gcm.gcmBitsPerPixel++;
378 		    gcm.gcmColorCount *= 2;
379 		    }
380 
381 		if  ( transparentColor >= gcm.gcmColorCount )
382 		    {
383 		    LDEB(transparentColor);
384 		    transparentColor= backgroundColor= gcm.gcmColorCount- 1;
385 		    }
386 		}
387 
388 	    break;
389 
390 	case BMcoRGB:
391 	    switch( bd->bdBitsPerPixel )
392 		{
393 		case 4:
394 		case 8:
395 		default:
396 		    LLDEB(bd->bdColorEncoding,bd->bdBitsPerPixel);
397 		    return -1;
398 		}
399 
400 	default:
401 	    LLDEB(bd->bdColorEncoding,bd->bdBitsPerPixel);
402 	    return -1;
403 	}
404 
405     if  ( bd->bdHasAlpha )
406 	{ bmGifSetVersion( gft, "89a" );	}
407     else{ bmGifSetVersion( gft, "87a" );	}
408 
409     if  ( EGifPutScreenDesc( gft, bd->bdPixelsWide, bd->bdPixelsHigh,
410 				    gcm.gcmBitsPerPixel, 0, &gcm ) != GIF_OK )
411 	{ LDEB(1); EGifCloseFile( gft ); return -1;	}
412 
413     if  ( bd->bdHasAlpha )
414 	{
415 	unsigned char	extension[4];
416 
417 	extension[0]= 0x01;
418 	extension[1]= 0;
419 	extension[2]= 0;
420 	extension[3]= transparentColor;
421 
422 	if  ( EGifPutExtension( gft, GRAPHICS_EXT_FUNC_CODE,
423 				sizeof(extension), extension ) != GIF_OK )
424 	    { LDEB(1); EGifCloseFile( gft ); return -1;	}
425 	}
426 
427     if  ( EGifPutImageDesc( gft, left, top,
428 				bd->bdPixelsWide, bd->bdPixelsHigh,
429 						interlace, &gcm ) != GIF_OK )
430 	{ LDEB(1); EGifCloseFile( gft ); return -1;	}
431 
432     if  ( bd->bdBitsPerPixel == 8 && ! bd->bdHasAlpha )
433 	{
434 	from= buffer;
435 	for ( row= 0; row < bd->bdPixelsHigh; row++ )
436 	    {
437 	    if  ( bmGifPutPixels( gft, (unsigned char *)from,
438 						bd->bdPixelsWide ) != GIF_OK )
439 		{ LDEB(row); EGifCloseFile( gft ); return -1; }
440 
441 	    from += bd->bdBytesPerRow;
442 	    }
443 	}
444     else{
445 	unsigned char *		line;
446 
447 	line= (unsigned char *)malloc( bd->bdPixelsWide+ 7 );
448 	if  ( ! line )
449 	    { XDEB(line); EGifCloseFile( gft ); return -1; }
450 
451 	switch( bd->bdBitsPerPixel )
452 	    {
453 	    case 1: case 2: case 4: case 8: case 16:
454 		for ( row= 0; row < bd->bdPixelsHigh; row++ )
455 		    {
456 		    from= buffer+ row* bd->bdBytesPerRow;
457 
458 		    bmInflateTo8bit( line, from, bd,
459 					    transparentColor, bd->bdHasAlpha );
460 
461 		    if  ( bmGifPutPixels( gft, line, bd->bdPixelsWide )
462 								    != GIF_OK )
463 			{
464 			LDEB(row);
465 			EGifCloseFile( gft ); free( line );
466 			return -1;
467 			}
468 		    }
469 		break;
470 
471 	    default:
472 		LDEB(bd->bdBitsPerPixel);
473 		EGifCloseFile( gft ); free( line );
474 		return -1;
475 	    }
476 
477 	free( line );
478 	}
479 
480     EGifCloseFile( gft );
481 
482     return 0;
483     }
484 
bmWriteGifFile(const MemoryBuffer * filename,const unsigned char * buffer,const BitmapDescription * bd,int privateFormat)485 int bmWriteGifFile(	const MemoryBuffer *		filename,
486 			const unsigned char *		buffer,
487 			const BitmapDescription *	bd,
488 			int				privateFormat )
489     {
490     SimpleOutputStream *	sos;
491 
492     if  ( bmCanWriteGifFile( bd, privateFormat ) )
493 	{ LDEB(1); return -1;	}
494 
495     sos= sioOutFileioOpen( filename );
496     if  ( ! sos )
497 	{ XDEB(sos); return -1;	}
498 
499     if  ( bmGifWriteGif( bd, buffer, sos ) )
500 	{ LDEB(1); sioOutClose( sos ); return -1;	}
501 
502     sioOutClose( sos );
503     return 0;
504     }
505 
506 /************************************************************************/
507 /*  Can this bitmap be written in GIF?					*/
508 /************************************************************************/
509 
bmCanWriteGifFile(const BitmapDescription * bd,int privateFormat)510 int bmCanWriteGifFile(	const BitmapDescription *	bd,
511 			int				privateFormat )
512     {
513     if  ( bd->bdBitsPerPixel <= 8 )
514 	{ return 0;	}
515 
516     if  ( bd->bdColorEncoding == BMcoRGB8PALETTE	&&
517 	  bd->bdHasAlpha				&&
518 	  bd->bdBitsPerPixel <= 16			)
519 	{ return 0;	}
520 
521     return -1;
522     }
523