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