1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/gifdecod.cpp
3 // Purpose: wxGIFDecoder, GIF reader for wxImage and wxAnimation
4 // Author: Guillermo Rodriguez Garcia <guille@iies.es>
7 // Copyright: (c) Guillermo Rodriguez Garcia
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_STREAMS && wxUSE_GIF
21 #include "wx/palette.h"
26 #include "wx/gifdecod.h"
30 //---------------------------------------------------------------------------
32 //---------------------------------------------------------------------------
34 // internal class for storing GIF image data
41 unsigned int w
; /* width */
42 unsigned int h
; /* height */
43 unsigned int left
; /* x coord (in logical screen) */
44 unsigned int top
; /* y coord (in logical screen) */
45 int transparent
; /* transparent color index (-1 = none) */
46 wxAnimationDisposal disposal
; /* disposal method */
47 long delay
; /* delay in ms (-1 = unused) */
48 unsigned char *p
; /* bitmap */
49 unsigned char *pal
; /* palette */
50 unsigned int ncolours
; /* number of colours */
52 DECLARE_NO_COPY_CLASS(GIFImage
)
57 //---------------------------------------------------------------------------
58 // GIFImage constructor
59 //---------------------------------------------------------------------------
67 disposal
= wxANIM_DONOTREMOVE
;
69 p
= (unsigned char *) NULL
;
70 pal
= (unsigned char *) NULL
;
74 //---------------------------------------------------------------------------
75 // wxGIFDecoder constructor and destructor
76 //---------------------------------------------------------------------------
78 wxGIFDecoder::wxGIFDecoder()
82 wxGIFDecoder::~wxGIFDecoder()
87 void wxGIFDecoder::Destroy()
89 wxASSERT(m_nFrames
==m_frames
.GetCount());
90 for (size_t i
=0; i
<m_nFrames
; i
++)
92 GIFImage
*f
= (GIFImage
*)m_frames
[i
];
103 //---------------------------------------------------------------------------
104 // Convert this image to a wxImage object
105 //---------------------------------------------------------------------------
107 // This function was designed by Vaclav Slavik
109 bool wxGIFDecoder::ConvertToImage(size_t frame
, wxImage
*image
) const
111 unsigned char *src
, *dst
, *pal
;
115 /* just in case... */
118 /* create the image */
119 wxSize sz
= GetFrameSize(frame
);
120 image
->Create(sz
.GetWidth(), sz
.GetHeight());
125 pal
= GetPalette(frame
);
126 src
= GetData(frame
);
127 dst
= image
->GetData();
128 transparent
= GetTransparentColourIndex(frame
);
130 /* set transparent colour mask */
131 if (transparent
!= -1)
133 for (i
= 0; i
< GetNcolours(frame
); i
++)
135 if ((pal
[3 * i
+ 0] == 255) &&
136 (pal
[3 * i
+ 1] == 0) &&
137 (pal
[3 * i
+ 2] == 255))
139 pal
[3 * i
+ 2] = 254;
143 pal
[3 * transparent
+ 0] = 255,
144 pal
[3 * transparent
+ 1] = 0,
145 pal
[3 * transparent
+ 2] = 255;
147 image
->SetMaskColour(255, 0, 255);
150 image
->SetMask(false);
153 unsigned char r
[256];
154 unsigned char g
[256];
155 unsigned char b
[256];
157 for (i
= 0; i
< 256; i
++)
164 image
->SetPalette(wxPalette(GetNcolours(frame
), r
, g
, b
));
165 #endif // wxUSE_PALETTE
167 /* copy image data */
168 unsigned long npixel
= sz
.GetWidth() * sz
.GetHeight();
169 for (i
= 0; i
< npixel
; i
++, src
++)
171 *(dst
++) = pal
[3 * (*src
) + 0];
172 *(dst
++) = pal
[3 * (*src
) + 1];
173 *(dst
++) = pal
[3 * (*src
) + 2];
180 //---------------------------------------------------------------------------
182 //---------------------------------------------------------------------------
184 #define GetFrame(n) ((GIFImage*)m_frames[n])
187 // Get data for current frame
189 wxSize
wxGIFDecoder::GetFrameSize(size_t frame
) const
191 return wxSize(GetFrame(frame
)->w
, GetFrame(frame
)->h
);
194 wxPoint
wxGIFDecoder::GetFramePosition(size_t frame
) const
196 return wxPoint(GetFrame(frame
)->left
, GetFrame(frame
)->top
);
199 wxAnimationDisposal
wxGIFDecoder::GetDisposalMethod(size_t frame
) const
201 return GetFrame(frame
)->disposal
;
204 long wxGIFDecoder::GetDelay(size_t frame
) const
206 return GetFrame(frame
)->delay
;
209 wxColour
wxGIFDecoder::GetTransparentColour(size_t frame
) const
211 unsigned char *pal
= GetFrame(frame
)->pal
;
212 int n
= GetFrame(frame
)->transparent
;
216 return wxColour(pal
[n
*3 + 0],
221 unsigned char* wxGIFDecoder::GetData(size_t frame
) const { return (GetFrame(frame
)->p
); }
222 unsigned char* wxGIFDecoder::GetPalette(size_t frame
) const { return (GetFrame(frame
)->pal
); }
223 unsigned int wxGIFDecoder::GetNcolours(size_t frame
) const { return (GetFrame(frame
)->ncolours
); }
224 int wxGIFDecoder::GetTransparentColourIndex(size_t frame
) const { return (GetFrame(frame
)->transparent
); }
228 //---------------------------------------------------------------------------
229 // GIF reading and decoding
230 //---------------------------------------------------------------------------
233 // Reads the next code from the file stream, with size 'bits'
235 int wxGIFDecoder::getcode(wxInputStream
& stream
, int bits
, int ab_fin
)
237 unsigned int mask
; /* bit mask */
238 unsigned int code
; /* code (result) */
240 /* get remaining bits from last byte read */
241 mask
= (1 << bits
) - 1;
242 code
= (m_lastbyte
>> (8 - m_restbits
)) & mask
;
244 /* keep reading new bytes while needed */
245 while (bits
> m_restbits
)
247 /* if no bytes left in this block, read the next block */
250 m_restbyte
= (unsigned char)stream
.GetC();
252 /* Some encoders are a bit broken: instead of issuing
253 * an end-of-image symbol (ab_fin) they come up with
254 * a zero-length subblock!! We catch this here so
255 * that the decoder sees an ab_fin code.
264 stream
.Read((void *) m_buffer
, m_restbyte
);
265 if (stream
.LastRead() != m_restbyte
)
273 /* read next byte and isolate the bits we need */
274 m_lastbyte
= (unsigned char) (*m_bufp
++);
275 mask
= (1 << (bits
- m_restbits
)) - 1;
276 code
= code
+ ((m_lastbyte
& mask
) << m_restbits
);
279 /* adjust total number of bits extracted from the buffer */
280 m_restbits
= m_restbits
+ 8;
283 /* find number of bits remaining for next code */
284 m_restbits
= (m_restbits
- bits
);
291 // GIF decoding function. The initial code size (aka root size)
292 // is 'bits'. Supports interlaced images (interl == 1).
293 // Returns wxGIF_OK (== 0) on success, or an error code if something
294 // fails (see header file for details)
295 wxGIFErrorCode
wxGIFDecoder::dgif(wxInputStream
& stream
, GIFImage
*img
, int interl
, int bits
)
297 static const int allocSize
= 4096 + 1;
298 int *ab_prefix
= new int[allocSize
]; /* alphabet (prefixes) */
299 if (ab_prefix
== NULL
)
304 int *ab_tail
= new int[allocSize
]; /* alphabet (tails) */
311 int *stack
= new int[allocSize
]; /* decompression stack */
319 int ab_clr
; /* clear code */
320 int ab_fin
; /* end of info code */
321 int ab_bits
; /* actual symbol width, in bits */
322 int ab_free
; /* first free position in alphabet */
323 int ab_max
; /* last possible character in alphabet */
324 int pass
; /* pass number in interlaced images */
325 int pos
; /* index into decompresion stack */
326 unsigned int x
, y
; /* position in image buffer */
328 int code
, readcode
, lastcode
, abcabca
;
330 /* these won't change */
331 ab_clr
= (1 << bits
);
332 ab_fin
= (1 << bits
) + 1;
334 /* these will change through the decompression proccess */
336 ab_free
= (1 << bits
) + 2;
337 ab_max
= (1 << ab_bits
) - 1;
343 /* reset decoder vars */
351 readcode
= code
= getcode(stream
, ab_bits
, ab_fin
);
354 if (code
== ab_fin
) break;
356 /* reset alphabet? */
359 /* reset main variables */
361 ab_free
= (1 << bits
) + 2;
362 ab_max
= (1 << ab_bits
) - 1;
366 /* skip to next code */
370 /* unknown code: special case (like in ABCABCA) */
373 code
= lastcode
; /* take last string */
374 stack
[pos
++] = abcabca
; /* add first character */
377 /* build the string for this code in the stack */
378 while (code
> ab_clr
)
380 stack
[pos
++] = ab_tail
[code
];
381 code
= ab_prefix
[code
];
383 // Don't overflow. This shouldn't happen with normal
384 // GIF files, the allocSize of 4096+1 is enough. This
385 // will only happen with badly formed GIFs.
386 if (pos
>= allocSize
)
391 return wxGIF_INVFORMAT
;
395 if (pos
>= allocSize
)
400 return wxGIF_INVFORMAT
;
403 stack
[pos
] = code
; /* push last code into the stack */
404 abcabca
= code
; /* save for special case */
406 /* make new entry in alphabet (only if NOT just cleared) */
409 // Normally, after the alphabet is full and can't grow any
410 // further (ab_free == 4096), encoder should (must?) emit CLEAR
411 // to reset it. This checks whether we really got it, otherwise
412 // the GIF is damaged.
413 if (ab_free
> ab_max
)
418 return wxGIF_INVFORMAT
;
421 // This assert seems unnecessary since the condition above
422 // eliminates the only case in which it went false. But I really
423 // don't like being forced to ask "Who in .text could have
424 // written there?!" And I wouldn't have been forced to ask if
425 // this line had already been here.
426 wxASSERT(ab_free
< allocSize
);
428 ab_prefix
[ab_free
] = lastcode
;
429 ab_tail
[ab_free
] = code
;
432 if ((ab_free
> ab_max
) && (ab_bits
< 12))
435 ab_max
= (1 << ab_bits
) - 1;
439 /* dump stack data to the image buffer */
442 (img
->p
)[x
+ (y
* (img
->w
))] = (char) stack
[pos
];
451 /* support for interlaced images */
454 case 1: y
+= 8; break;
455 case 2: y
+= 8; break;
456 case 3: y
+= 4; break;
457 case 4: y
+= 2; break;
460 /* loop until a valid y coordinate has been
461 found, Or if the maximum number of passes has
462 been reached, exit the loop, and stop image
463 decoding (At this point the image is successfully
465 If we don't loop, but merely set y to some other
466 value, that new value might still be invalid depending
467 on the height of the image. This would cause out of
470 while (y
>= (img
->h
))
474 case 2: y
= 4; break;
475 case 3: y
= 2; break;
476 case 4: y
= 1; break;
480 It's possible we arrive here. For example this
481 happens when the image is interlaced, and the
482 height is 1. Looking at the above cases, the
483 lowest possible y is 1. While the only valid
484 one would be 0 for an image of height 1. So
485 'eventually' the loop will arrive here.
486 This case makes sure this while loop is
487 exited, as well as the 2 other ones.
490 // Set y to a valid coordinate so the local
491 // while loop will be exited. (y = 0 always
492 // is >= img->h since if img->h == 0 the
493 // image is never decoded)
496 // This will exit the other outer while loop
499 // This will halt image decoding.
511 Normally image decoding is finished when an End of Information code is
512 encountered (code == ab_fin) however some broken encoders write wrong
513 "block byte counts" (The first byte value after the "code size" byte),
514 being one value too high. It might very well be possible other variants
515 of this problem occur as well. The only sensible solution seems to
516 be to check for clipping.
517 Example of wrong encoding:
518 (1 * 1 B/W image, raster data stream follows in hex bytes)
520 02 << B/W images have a code size of 2
521 02 << Block byte count
523 00 << Zero byte count (terminates data stream)
525 Because the block byte count is 2, the zero byte count is used in the
526 decoding process, and decoding is continued after this byte. (While it
527 should signal an end of image)
533 01 << When decoded this correctly includes the End of Information code
541 (The 44 doesn't include an End of Information code, but at least the
542 decoder correctly skips to 00 now after decoding, and signals this
543 as an End of Information itself)
557 while (code
!= ab_fin
);
559 delete [] ab_prefix
;
568 // Returns true if the file looks like a valid GIF, false otherwise.
570 bool wxGIFDecoder::CanRead(wxInputStream
&stream
) const
572 unsigned char buf
[3];
574 if ( !stream
.Read(buf
, WXSIZEOF(buf
)) )
577 stream
.SeekI(-(wxFileOffset
)WXSIZEOF(buf
), wxFromCurrent
);
579 return memcmp(buf
, "GIF", WXSIZEOF(buf
)) == 0;
584 // Reads and decodes one or more GIF images, depending on whether
585 // animated GIF support is enabled. Can read GIFs with any bit
586 // size (color depth), but the output images are always expanded
587 // to 8 bits per pixel. Also, the image palettes always contain
588 // 256 colors, although some of them may be unused. Returns wxGIF_OK
589 // (== 0) on success, or an error code if something fails (see
590 // header file for details)
592 wxGIFErrorCode
wxGIFDecoder::LoadGIF(wxInputStream
& stream
)
594 unsigned int global_ncolors
= 0;
595 int bits
, interl
, transparent
, i
;
596 wxAnimationDisposal disposal
;
599 unsigned char type
= 0;
600 unsigned char pal
[768];
601 unsigned char buf
[16];
604 /* check GIF signature */
605 if (!CanRead(stream
))
606 return wxGIF_INVFORMAT
;
608 /* check for animated GIF support (ver. >= 89a) */
610 static const size_t headerSize
= (3 + 3);
611 stream
.Read(buf
, headerSize
);
612 if (stream
.LastRead() != headerSize
)
614 return wxGIF_INVFORMAT
;
617 if (memcmp(buf
+ 3, "89a", 3) < 0)
622 /* read logical screen descriptor block (LSDB) */
623 static const size_t lsdbSize
= (2 + 2 + 1 + 1 + 1);
624 stream
.Read(buf
, lsdbSize
);
625 if (stream
.LastRead() != lsdbSize
)
627 return wxGIF_INVFORMAT
;
630 m_szAnimation
.SetWidth( buf
[0] + 256 * buf
[1] );
631 m_szAnimation
.SetHeight( buf
[2] + 256 * buf
[3] );
633 if ((m_szAnimation
.GetWidth() == 0) || (m_szAnimation
.GetHeight() == 0))
635 return wxGIF_INVFORMAT
;
638 /* load global color map if available */
639 if ((buf
[4] & 0x80) == 0x80)
641 int backgroundColIndex
= buf
[5];
643 global_ncolors
= 2 << (buf
[4] & 0x07);
644 size_t numBytes
= 3 * global_ncolors
;
645 stream
.Read(pal
, numBytes
);
646 if (stream
.LastRead() != numBytes
)
648 return wxGIF_INVFORMAT
;
651 m_background
.Set(pal
[backgroundColIndex
*3 + 0],
652 pal
[backgroundColIndex
*3 + 1],
653 pal
[backgroundColIndex
*3 + 2]);
656 /* transparent colour, disposal method and delay default to unused */
658 disposal
= wxANIM_UNSPECIFIED
;
664 type
= (unsigned char)stream
.GetC();
667 If the end of file has been reached (or an error) and a ";"
668 (0x3B) hasn't been encountered yet, exit the loop. (Without this
669 check the while loop would loop endlessly.) Later on, in the next while
670 loop, the file will be treated as being truncated (But still
671 be decoded as far as possible). returning wxGIF_TRUNCATED is not
672 possible here since some init code is done after this loop.
674 if (stream
.Eof())// || !stream.IsOk())
677 type is set to some bogus value, so there's no
678 need to continue evaluating it.
680 break; // Alternative : "return wxGIF_INVFORMAT;"
689 /* extension block? */
692 if (((unsigned char)stream
.GetC()) == 0xF9)
693 /* graphics control extension, parse it */
695 static const size_t gceSize
= 6;
696 stream
.Read(buf
, gceSize
);
697 if (stream
.LastRead() != gceSize
)
700 return wxGIF_INVFORMAT
;
703 /* read delay and convert from 1/100 of a second to ms */
704 delay
= 10 * (buf
[2] + 256 * buf
[3]);
706 /* read transparent colour index, if used */
708 transparent
= buf
[4];
710 /* read disposal method */
711 disposal
= (wxAnimationDisposal
)(((buf
[1] & 0x1C) >> 2) - 1);
714 /* other extension, skip */
716 while ((i
= (unsigned char)stream
.GetC()) != 0)
718 if (stream
.Eof() || (stream
.LastRead() == 0))
723 stream
.SeekI(i
, wxFromCurrent
);
728 /* image descriptor block? */
731 /* allocate memory for IMAGEN struct */
732 GIFImage
*pimg
= new GIFImage();
740 /* fill in the data */
741 static const size_t idbSize
= (2 + 2 + 2 + 2 + 1);
742 stream
.Read(buf
, idbSize
);
743 if (stream
.LastRead() != idbSize
)
746 return wxGIF_INVFORMAT
;
749 pimg
->left
= buf
[0] + 256 * buf
[1];
750 pimg
->top
= buf
[2] + 256 * buf
[3];
752 pimg->left = buf[4] + 256 * buf[5];
753 pimg->top = buf[4] + 256 * buf[5];
755 pimg
->w
= buf
[4] + 256 * buf
[5];
756 pimg
->h
= buf
[6] + 256 * buf
[7];
758 if ((pimg
->w
== 0) || (pimg
->w
> (unsigned int)m_szAnimation
.GetWidth()) ||
759 (pimg
->h
== 0) || (pimg
->h
> (unsigned int)m_szAnimation
.GetHeight()))
762 return wxGIF_INVFORMAT
;
765 interl
= ((buf
[8] & 0x40)? 1 : 0);
766 size
= pimg
->w
* pimg
->h
;
768 pimg
->transparent
= transparent
;
769 pimg
->disposal
= disposal
;
772 /* allocate memory for image and palette */
773 pimg
->p
= (unsigned char *) malloc((size_t)size
);
774 pimg
->pal
= (unsigned char *) malloc(768);
776 if ((!pimg
->p
) || (!pimg
->pal
))
782 /* load local color map if available, else use global map */
783 if ((buf
[8] & 0x80) == 0x80)
785 unsigned int local_ncolors
= 2 << (buf
[8] & 0x07);
786 size_t numBytes
= 3 * local_ncolors
;
787 stream
.Read(pimg
->pal
, numBytes
);
788 pimg
->ncolours
= local_ncolors
;
789 if (stream
.LastRead() != numBytes
)
792 return wxGIF_INVFORMAT
;
797 memcpy(pimg
->pal
, pal
, 768);
798 pimg
->ncolours
= global_ncolors
;
801 /* get initial code size from first byte in raster data */
802 bits
= (unsigned char)stream
.GetC();
806 return wxGIF_INVFORMAT
;
810 wxGIFErrorCode result
= dgif(stream
, pimg
, interl
, bits
);
811 if (result
!= wxGIF_OK
)
817 /* add the image to our frame array */
818 m_frames
.Add((void*)pimg
);
821 /* if this is not an animated GIF, exit after first image */
830 return wxGIF_INVFORMAT
;
833 /* try to read to the end of the stream */
837 return wxGIF_TRUNCATED
;
839 type
= (unsigned char)stream
.GetC();
844 (void) stream
.GetC();
847 while ((i
= (unsigned char)stream
.GetC()) != 0)
849 if (stream
.Eof() || (stream
.LastRead() == 0))
852 return wxGIF_INVFORMAT
;
854 stream
.SeekI(i
, wxFromCurrent
);
857 else if (type
== 0x2C)
859 /* image descriptor block */
860 static const size_t idbSize
= (2 + 2 + 2 + 2 + 1);
861 stream
.Read(buf
, idbSize
);
862 if (stream
.LastRead() != idbSize
)
865 return wxGIF_INVFORMAT
;
868 /* local color map */
869 if ((buf
[8] & 0x80) == 0x80)
871 unsigned int local_ncolors
= 2 << (buf
[8] & 0x07);
872 wxFileOffset numBytes
= 3 * local_ncolors
;
873 stream
.SeekI(numBytes
, wxFromCurrent
);
876 /* initial code size */
877 (void) stream
.GetC();
878 if (stream
.Eof() || (stream
.LastRead() == 0))
881 return wxGIF_INVFORMAT
;
885 while ((i
= (unsigned char)stream
.GetC()) != 0)
887 if (stream
.Eof() || (stream
.LastRead() == 0))
890 return wxGIF_INVFORMAT
;
892 stream
.SeekI(i
, wxFromCurrent
);
895 else if ((type
!= 0x3B) && (type
!= 00)) /* testing */
897 /* images are OK, but couldn't read to the end of the stream */
898 return wxGIF_TRUNCATED
;
905 #endif // wxUSE_STREAMS && wxUSE_GIF