1 /********************************************************************************
2 * *
3 * G I F I n p u t / O u t p u t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1998,2006 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 *********************************************************************************
22 * $Id: fxgifio.cpp 3297 2015-12-14 20:30:04Z arthurcnorman $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXStream.h"
29 #include "fxpriv.h"
30
31
32 /*
33 Notes:
34
35 - "The Graphics Interchange Format(c) is the Copyright property of
36 CompuServe Incorporated. GIF(sm) is a Service Mark property of
37 CompuServe Incorporated."
38
39 - Make sure reading and writing GIF transfers same number of bytes
40 from/to the stream.
41
42 - For a transparent pixel, we zero out the alpha channel but leave
43 the RGB intact; this way, we can maintain the original RGB data.
44
45 - The interleaving works as follows:
46
47 Pass1 Pass2 Pass3 Pass4
48 Start 0 4 3 1
49 Step 8 8 4 2
50
51 - LZW Patent has expired 6/20/2003; so compression now implemented.
52 */
53
54
55 using namespace FX;
56
57 /*******************************************************************************/
58
59 namespace FX {
60
61
62 extern FXAPI bool fxcheckGIF(FXStream& store);
63 extern FXAPI bool fxloadGIF(FXStream& store,FXColor*& data,FXint& width,FXint& height);
64 extern FXAPI bool fxsaveGIF(FXStream& store,const FXColor *data,FXint width,FXint height,bool fast=true);
65
66
67 // Codes found in the GIF specification
68 const FXuchar TAG_EXTENSION = 0x21; // Extension block
69 const FXuchar TAG_GRAPHIC = 0xF9; // Graphic control block
70 const FXuchar TAG_IMAGE = 0x2c; // Image separator
71 const FXuchar TAG_TERMINATOR = 0x00; // Block terminator
72 const FXuchar TAG_GRAPHICSIZE = 0x04; // Graphic block size
73 const FXuchar TAG_IMAGEFLAGS = 0x00; // Image flags
74 const FXuchar TAG_ZERO = 0x00; // Just a zero
75 const FXuchar TAG_ENDFILE = 0x3B; // End of file
76 const FXuchar TAG_TRANSPARENT = 0x01; // Transparent flag
77 const FXuchar TAG_SIG1 = 0x47; // Signature G
78 const FXuchar TAG_SIG2 = 0x49; // Signature I
79 const FXuchar TAG_SIG3 = 0x46; // Signature F
80 const FXuchar TAG_VER = 0x38; // Version byte
81 const FXuchar TAG_NEW = 0x39; // New version
82 const FXuchar TAG_OLD = 0x37; // Old version
83 const FXuchar TAG_SUF = 0x61; // Version suffix
84
85
86 // Check if stream contains a GIF
fxcheckGIF(FXStream & store)87 bool fxcheckGIF(FXStream& store){
88 FXuchar signature[3];
89 store.load(signature,3);
90 store.position(-3,FXFromCurrent);
91 return signature[0]==TAG_SIG1 && signature[1]==TAG_SIG2 && signature[2]==TAG_SIG3;
92 }
93
94
95 // Load image from stream
fxloadGIF(FXStream & store,FXColor * & data,FXint & width,FXint & height)96 bool fxloadGIF(FXStream& store,FXColor*& data,FXint& width,FXint& height){
97 const FXint Yinit[4]={0,4,2,1};
98 const FXint Yinc[4]={8,8,4,2};
99 FXint imwidth,imheight,interlace,ncolors,npixels,maxpixels,i;
100 FXuchar c1,c2,c3,sbsize,flags,alpha,*ptr,*buf,*pix;
101 FXColor colormap[256];
102 FXint BitOffset; // Bit Offset of next code
103 FXint ByteOffset; // Byte offset of next code
104 FXint XC,YC; // Output X and Y coords of current pixel
105 FXint Pass; // Used by output routine if interlaced pic
106 FXint OutCount; // Decompressor output 'stack count'
107 FXint CodeSize; // Code size, read from GIF header
108 FXint InitCodeSize; // Starting code size, used during Clear
109 FXint Code; // Value returned by ReadCode
110 FXint MaxCode; // limiting value for current code size
111 FXint ClearCode; // GIF clear code
112 FXint EOFCode; // GIF end-of-information code
113 FXint CurCode,OldCode,InCode; // Decompressor variables
114 FXint FirstFree; // First free code, generated per GIF spec
115 FXint FreeCode; // Decompressor,next free slot in hash table
116 FXint FinChar; // Decompressor variable
117 FXint BitMask; // AND mask for data size
118 FXint ReadMask; // Code AND mask for current code size
119 FXint Prefix[4096]; // The hash table used by the decompressor
120 FXint Suffix[4096]; // The hash table used by the decompressor
121 FXint OutCode[4097]; // An output array used by the decompressor
122
123 // Null out
124 data=NULL;
125 width=0;
126 height=0;
127
128 // Load signature
129 store >> c1;
130 store >> c2;
131 store >> c3;
132
133 // Check signature
134 if(c1!=TAG_SIG1 || c2!=TAG_SIG2 || c3!=TAG_SIG3) return false;
135
136 // Load version
137 store >> c1;
138 store >> c2;
139 store >> c3;
140
141 // Check version
142 if(c1!=TAG_VER || (c2!=TAG_OLD && c2!=TAG_NEW) || c3!=TAG_SUF) return false;
143
144 // Get screen descriptor
145 store >> c1 >> c2; // Skip screen width
146 store >> c1 >> c2; // Skip screen height
147 store >> flags; // Get flags
148 store >> alpha; // Background
149 store >> c2; // Skip aspect ratio
150
151 // Determine number of colors
152 ncolors=2<<(flags&7);
153 BitMask=ncolors-1;
154
155 // If no colormap, spec says first 2 colors are black and white
156 colormap[0]=FXRGB(0,0,0);
157 colormap[1]=FXRGB(255,255,255);
158
159 // Read global map if there is one
160 if(flags&0x80){
161 for(i=0; i<ncolors; i++){
162 store >> ((FXuchar*)(colormap+i))[0]; // Blue
163 store >> ((FXuchar*)(colormap+i))[1]; // Green
164 store >> ((FXuchar*)(colormap+i))[2]; // Red
165 ((FXuchar*)(colormap+i))[3]=255; // Alpha
166 }
167 }
168
169 // Process it
170 while(1){
171 store >> c1;
172 if(c1==TAG_EXTENSION){
173
174 // Read extension code
175 store >> c2;
176
177 // Graphic Control Extension
178 if(c2==TAG_GRAPHIC){
179 store >> sbsize;
180 if(sbsize!=TAG_GRAPHICSIZE) return false;
181 store >> flags; // Flags
182 store >> c3 >> c3; // Delay time
183 store >> alpha; // Alpha color index; we suspect alpha<ncolors not always true...
184 store >> c3;
185 if(flags&1){ // Clear alpha channel of alpha color
186 colormap[alpha]&=FXRGBA(255,255,255,0); // Clear the alpha channel but keep the RGB
187 }
188 continue;
189 }
190
191 // Other extension
192 do{
193 store >> sbsize;
194 store.position(store.position()+sbsize);
195 }
196 while(sbsize>0 && !store.eof()); // FIXME this logic still flawed
197 continue;
198 }
199
200 // Image separator
201 if(c1==TAG_IMAGE){
202 store >> c1 >> c2;
203 store >> c1 >> c2;
204
205 // Get image width
206 store >> c1 >> c2;
207 imwidth=(c2<<8)+c1;
208
209 // Get image height
210 store >> c1 >> c2;
211 imheight=(c2<<8)+c1;
212
213 // Get image flags
214 store >> flags;
215
216 // Read local map if there is one
217 if(flags&0x80){
218 ncolors=2<<(flags&7);
219 for(i=0; i<ncolors; i++){
220 store >> ((FXuchar*)(colormap+i))[0]; // Red
221 store >> ((FXuchar*)(colormap+i))[1]; // Green
222 store >> ((FXuchar*)(colormap+i))[2]; // Blue
223 ((FXuchar*)(colormap+i))[3]=255; // Alpha
224 }
225 }
226
227 // Interlaced image
228 interlace=(flags&0x40);
229
230 // Total pixels expected
231 maxpixels=imwidth*imheight;
232
233 // Allocate memory
234 if(!FXMALLOC(&data,FXColor,maxpixels)) return false;
235
236 // Set up pointers; we're using the first 3/4 of the
237 // data array for the compressed data, and the latter 1/4 for
238 // the 8-bit pixel data. At the end of the decompression, we
239 // overwrite the data array with the 32-bit RGBA data.
240 // Note that the unGIF "compressed" data may be larger than
241 // the uncompressed data, hence the large safety factor...
242 buf=(FXuchar*)data;
243 pix=buf+maxpixels+maxpixels+maxpixels;
244
245 // Start reading the raster data. First we get the intial code size
246 // and compute decompressor constant values, based on this code size.
247 store >> c1;
248 CodeSize=c1;
249
250 ClearCode=1<<CodeSize;
251 EOFCode=ClearCode+1;
252 FreeCode=FirstFree=ClearCode+2;
253
254 // The GIF spec has it that the code size is the code size used to
255 // compute the above values is the code size given in the file, but the
256 // code size used in compression/decompression is the code size given in
257 // the file plus one.
258 CodeSize++;
259 InitCodeSize=CodeSize;
260 MaxCode=1<<CodeSize;
261 ReadMask=MaxCode-1;
262
263 // Maximum code should not exceed 4096
264 if(MaxCode>=4096){ FXFREE(&data); return false; }
265
266 // Read all blocks of compressed data into one single buffer.
267 // We have an extra test to make sure we don't write past 3/4
268 // of the buffer:- this could happen in malicious GIF images!
269 ptr=buf;
270 do{
271 store >> sbsize;
272 if(ptr+sbsize>pix){ FXFREE(&data); return false; }
273 store.load(ptr,sbsize);
274 ptr+=sbsize;
275 }
276 while(sbsize>0 && !store.eof()); // FIXME this logic still flawed
277
278 // Initialize
279 BitOffset=XC=YC=Pass=OutCount=OldCode=FinChar=npixels=0;
280
281 // Drop 8-bit pixels in the upper part
282 ptr=pix;
283
284 // Decompress the file, continuing until you see the GIF EOF code.
285 // One obvious enhancement is to add checking for corrupt files here.
286 while(1){
287
288 // Fetch the next code from the raster data stream. The codes can be
289 // any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
290 // maintain our location in the source array as a BIT Offset. We compute
291 // the byte Offset into the raster array by dividing this by 8, pick up
292 // three bytes, compute the bit Offset into our 24-bit chunk, shift to
293 // bring the desired code to the bottom, then mask it off and return it.
294 ByteOffset=BitOffset>>3;
295 Code=(FXuint)buf[ByteOffset]+(((FXuint)buf[ByteOffset+1])<<8)+(((FXuint)buf[ByteOffset+2])<<16);
296 Code>>=(BitOffset&7);
297 BitOffset+=CodeSize;
298 Code&=ReadMask;
299
300 // Are we done?
301 if(Code==EOFCode || npixels>=maxpixels) break;
302
303 // Clear code sets everything back to its initial value, then reads the
304 // immediately subsequent code as uncompressed data.
305 if(Code==ClearCode){
306 CodeSize=InitCodeSize;
307 MaxCode=1<<CodeSize;
308 ReadMask=MaxCode-1;
309 FreeCode=FirstFree;
310
311 // Get next code
312 ByteOffset=BitOffset>>3;
313 Code=(FXuint)buf[ByteOffset]+(((FXuint)buf[ByteOffset+1])<<8)+(((FXuint)buf[ByteOffset+2])<<16);
314 Code>>=(BitOffset&7);
315 BitOffset+=CodeSize;
316 Code&=ReadMask;
317
318 CurCode=OldCode=Code;
319 FinChar=CurCode&BitMask;
320
321 if(!interlace){
322 *ptr++=FinChar;
323 }
324 else{
325 FXASSERT(0<=YC && YC<imheight);
326 FXASSERT(0<=XC && XC<imwidth);
327 ptr[YC*imwidth+XC]=FinChar;
328 XC+=1;
329 if(XC>=imwidth){
330 XC=0;
331 YC+=Yinc[Pass];
332 if(YC>=imheight){
333 Pass++;
334 YC=Yinit[Pass&3];
335 }
336 }
337 }
338 npixels++;
339 }
340
341 // If not a clear code, must be data: save same as CurCode and InCode
342 else{
343
344 // If we're at maxcode and didn't get a clear, stop loading
345 if(FreeCode>=4096){ FXFREE(&data); return false; }
346
347 CurCode=InCode=Code;
348
349 // If greater or equal to FreeCode, not in the hash table yet; repeat the last character decoded
350 if(CurCode>=FreeCode){
351 CurCode=OldCode;
352 if(OutCount>4096){ FXFREE(&data); return false; }
353 OutCode[OutCount++]=FinChar;
354 }
355
356 // Unless this code is raw data, pursue the chain pointed to by CurCode
357 // through the hash table to its end; each code in the chain puts its
358 // associated output code on the output queue.
359 while(CurCode>=ClearCode){
360 if(OutCount>4096 || CurCode>=FreeCode){ FXFREE(&data); return false; }
361 OutCode[OutCount++]=Suffix[CurCode];
362 CurCode=Prefix[CurCode];
363 }
364
365 if(OutCount>4096){ FXFREE(&data); return false; }
366
367 // The last code in the chain is treated as raw data
368 FinChar=CurCode&BitMask;
369 OutCode[OutCount++]=FinChar;
370
371 // Now we put the data out to the Output routine.
372 // It's been stacked LIFO, so deal with it that way...
373
374 // safety thing: prevent exceeding range
375 if(npixels+OutCount>maxpixels) OutCount=maxpixels-npixels;
376
377 npixels+=OutCount;
378 if(!interlace){
379 for(i=OutCount-1; i>=0; i--){
380 *ptr++=OutCode[i];
381 }
382 }
383 else{
384 for(i=OutCount-1; i>=0; i--){
385 FXASSERT(0<=YC && YC<imheight);
386 FXASSERT(0<=XC && XC<imwidth);
387 ptr[YC*imwidth+XC]=OutCode[i];
388 XC+=1;
389 if(XC>=imwidth){
390 XC=0;
391 YC+=Yinc[Pass];
392 if(YC>=imheight){
393 Pass++;
394 YC=Yinit[Pass&3];
395 }
396 }
397 }
398 }
399 OutCount=0;
400
401 // Build the hash table on-the-fly. No table is stored in the file
402 Prefix[FreeCode]=OldCode;
403 Suffix[FreeCode]=FinChar;
404 OldCode=InCode;
405
406 // Point to the next slot in the table. If we exceed the current
407 // MaxCode value, increment the code size unless it's already 12. If it
408 // is, do nothing: the next code decompressed better be CLEAR
409 FreeCode++;
410 if(FreeCode>=MaxCode){
411 if(CodeSize<12){
412 CodeSize++;
413 MaxCode*=2;
414 ReadMask=(1<<CodeSize)-1;
415 }
416 }
417 }
418 }
419
420 // Did the stream stop prematurely?
421 if(npixels!=maxpixels){
422 fxwarning("fxloadGIF: image truncated\n");
423 }
424
425 width=imwidth;
426 height=imheight;
427
428 // Technically, this is incorrect; but we have so
429 // many GIF87a's that we have to keep doing this!
430 colormap[alpha]&=FXRGBA(255,255,255,0);
431
432 // Apply colormap
433 for(i=0; i<maxpixels; i++){
434 data[i]=colormap[pix[i]];
435 }
436
437 // Skip image terminator to fully read all bytes
438 store >> c1;
439
440 return true;
441 }
442
443 // Non of the above, we fail!
444 return false;
445 }
446
447 // Shouldn't get here, but to satisfy compiler
448 return false;
449 }
450
451
452 /*******************************************************************************/
453
454
455 // Save a gif file to a stream
fxsaveGIF(FXStream & store,const FXColor * data,FXint width,FXint height,bool fast)456 bool fxsaveGIF(FXStream& store,const FXColor *data,FXint width,FXint height,bool fast){
457 FXuint clearcode,endcode,freecode,findcode,prefix,current,outaccu,initcodesize,codesize,hash,step;
458 FXint maxpixels,ncolors,bitsperpixel,colormapsize,outbits,src,dst,i;
459 FXuchar c1,c2,alpha,*pixels,*output;
460 FXColor colormap[256];
461 FXuint hashtab[5003];
462 FXushort codetab[5003];
463
464 // Must make sense
465 if(!data || width<=0 || height<=0) return false;
466
467 // How many pixels
468 maxpixels=width*height;
469
470 // Allocate temp buffer for pixels
471 if(!FXMALLOC(&output,FXuchar,(maxpixels<<1))) return false;
472 pixels=output+maxpixels;
473
474 // First, try EZ quantization, because it is exact; a previously
475 // loaded GIF will be re-saved with exactly the same colors.
476 if(!fxezquantize(pixels,data,colormap,ncolors,width,height,256)){
477 if(fast){
478 fxfsquantize(pixels,data,colormap,ncolors,width,height,256);
479 }
480 else{
481 fxwuquantize(pixels,data,colormap,ncolors,width,height,256);
482 }
483 }
484
485 // File signature
486 store << TAG_SIG1;
487 store << TAG_SIG2;
488 store << TAG_SIG3;
489
490 // File version
491 store << TAG_VER;
492 store << TAG_NEW;
493 store << TAG_SUF;
494
495 // Figure out bits per pixel
496 for(bitsperpixel=1; ncolors>(1<<bitsperpixel); bitsperpixel++);
497
498 // Colormap size
499 colormapsize=1<<bitsperpixel;
500
501 // Screen header
502 c1=width;
503 c2=width>>8;
504 store << c1 << c2; // Width
505 c1=height;
506 c2=height>>8;
507 store << c1 << c2; // Height
508 c1=0x80; // There is a color map
509 c1|=(bitsperpixel-1)<<4; // Number of bits of color resolution
510 c1|=(bitsperpixel-1); // The size (in bits) of the colormap
511 store << c1; // Flags
512 store << TAG_ZERO; // Background color
513 store << TAG_ZERO; // Aspect Ratio is none
514
515 // Output colormap
516 for(i=0; i<colormapsize; i++){
517 store << ((FXuchar*)(colormap+i))[0]; // Blue
518 store << ((FXuchar*)(colormap+i))[1]; // Green
519 store << ((FXuchar*)(colormap+i))[2]; // Red
520 }
521
522 // Output Graphics Control Extension, if alpha is present
523 for(i=0,alpha=0; i<ncolors; i++){
524 if(((FXuchar*)(colormap+i))[3]==0){
525 alpha=i;
526 store << TAG_EXTENSION; // Extension Introducer
527 store << TAG_GRAPHIC; // Graphic Control Label
528 store << TAG_GRAPHICSIZE; // Block Size
529 store << TAG_TRANSPARENT; // Disposal Method
530 store << TAG_ZERO; // Delay Time
531 store << TAG_ZERO;
532 store << alpha; // Transparent color index
533 store << TAG_TERMINATOR; // Block Terminator
534 break;
535 }
536 }
537
538 // Image descriptor
539 store << TAG_IMAGE; // Image separator
540 store << TAG_ZERO; // Image offset X
541 store << TAG_ZERO;
542 store << TAG_ZERO; // Image offset Y
543 store << TAG_ZERO;
544 c1=width;
545 c2=width>>8;
546 store << c1 << c2; // Width
547 c1=height;
548 c2=height>>8;
549 store << c1 << c2; // Height
550 store << TAG_IMAGEFLAGS; // Flags: no local map, no interlace
551
552 // Figure out code size and stuff
553 initcodesize=(bitsperpixel<=1)?2:bitsperpixel;
554 codesize=initcodesize+1;
555 clearcode=1<<(codesize-1);
556 endcode=clearcode+1;
557
558 // Now for the beef...
559 c1=initcodesize;
560 store << c1; // Write the Code size
561
562 // Clear hash table
563 memset(hashtab,0xff,sizeof(hashtab));
564 freecode=clearcode+2;
565
566 // Output clear code
567 FXASSERT(clearcode<(1u<<codesize));
568 outaccu=clearcode;
569 outbits=codesize;
570
571 // Compress image
572 src=dst=0;
573 prefix=pixels[src++];
574 while(1){
575
576 // Flush filled out bytes
577 while(outbits>=8){
578 output[dst++]=(FXuchar)outaccu;
579 outaccu>>=8;
580 outbits-=8;
581 }
582
583 // Done yet
584 if(src>=maxpixels) break;
585
586 // Get next pixel
587 current=pixels[src++];
588
589 // Check if in hash table
590 findcode=(current<<12)+prefix;
591 hash=findcode%5003; // 0<=hash<=5002
592 step=findcode%4999+1; // 1<=step<=4999
593 while(hashtab[hash]!=0xffffffff){ // Occupied slot?
594 if(hashtab[hash]==findcode){ // Existing prefix
595 prefix=codetab[hash]; // Code for prefix
596 goto nxt;
597 }
598 hash=(hash+step)%5003;
599 }
600
601 // Output prefix code
602 FXASSERT(prefix<(1u<<codesize));
603 FXASSERT(outbits+codesize<=32);
604 outaccu|=prefix<<outbits;
605 outbits+=codesize;
606
607 // New prefix code
608 prefix=current;
609
610 // If still room, enter into hash table
611 if(freecode<4096){ // Add to hash table
612 if(freecode>=(1u<<codesize) && codesize<12u) codesize++;
613 codetab[hash]=freecode++;
614 hashtab[hash]=findcode;
615 }
616
617 // Else issue clear code
618 else{
619 FXASSERT(clearcode<(1u<<codesize));
620 FXASSERT(outbits+codesize<=32);
621 outaccu|=clearcode<<outbits;
622 outbits+=codesize;
623
624 // Clear hash table
625 memset(hashtab,0xff,sizeof(hashtab));
626 freecode=clearcode+2;
627 codesize=initcodesize+1;
628 }
629
630 // Next pixel
631 nxt:continue;
632 }
633
634 // Output final prefix code
635 FXASSERT(prefix<(1u<<codesize));
636 FXASSERT(outbits+codesize<=32);
637 outaccu|=prefix<<outbits;
638 outbits+=codesize;
639
640 // Output end code
641 FXASSERT(endcode<(1u<<codesize));
642 FXASSERT(outbits+codesize<=32);
643 outaccu|=endcode<<outbits;
644 outbits+=codesize;
645
646 // FLush remaining bits out
647 while(outbits>0){
648 output[dst++]=(FXuchar)outaccu;
649 outaccu>>=8;
650 outbits-=8;
651 }
652
653 // Write blocks
654 for(src=0; src<dst; src+=c1){
655 c1=FXMIN(255,(dst-src));
656 store << c1;
657 store.save(&output[src],c1);
658 }
659
660 // Trailer
661 store << TAG_TERMINATOR; // Block terminator
662 store << TAG_ENDFILE; // File terminator
663
664 // Free storage
665 FXFREE(&output);
666 return true;
667 }
668
669
670 }
671
672