]> git.saurik.com Git - wxWidgets.git/blame - src/common/gifdecod.cpp
Fixed a bug in the latest 'micro optimization' - was skipping one
[wxWidgets.git] / src / common / gifdecod.cpp
CommitLineData
464122b6
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: gifdecod.cpp
3// Purpose: wxGIFDecoder, GIF reader for wxImage and wxAnimation
4// Author: Guillermo Rodriguez Garcia <guille@iies.es>
9d0e21da
GRG
5// Version: 3.04
6// RCS-ID: $Id$
464122b6
JS
7// Copyright: (c) Guillermo Rodriguez Garcia
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11#ifdef __GNUG__
12#pragma implementation "gifdecod.h"
13#endif
14
15// For compilers that support precompilation, includes "wx.h".
16#include "wx/wxprec.h"
17
18#ifdef __BORLANDC__
19# pragma hdrstop
20#endif
21
22#ifndef WX_PRECOMP
7be110e3 23# include "wx/defs.h"
464122b6
JS
24#endif
25
7be110e3 26#if wxUSE_STREAMS && wxUSE_GIF
464122b6
JS
27
28#include <stdlib.h>
29#include <string.h>
464122b6 30#include "wx/gifdecod.h"
2ce0a6e2 31
464122b6
JS
32
33//---------------------------------------------------------------------------
34// wxGIFDecoder constructor and destructor
35//---------------------------------------------------------------------------
36
37wxGIFDecoder::wxGIFDecoder(wxInputStream *s, bool anim)
38{
9742d3cc 39 m_f = s;
464122b6
JS
40 m_anim = anim;
41
42 m_background = -1;
43 m_screenw = 0;
44 m_screenh = 0;
45
46 m_pimage = NULL;
47 m_pfirst = NULL;
48 m_plast = NULL;
49 m_image = 0;
50 m_nimages = 0;
51}
52
53wxGIFDecoder::~wxGIFDecoder()
54{
55 Destroy();
56}
57
58void wxGIFDecoder::Destroy()
59{
e4b8154a 60 GIFImage *pimg, *paux;
464122b6
JS
61
62 pimg = m_pfirst;
63
64 while (pimg != NULL)
65 {
66 paux = pimg->next;
67 free(pimg->p);
68 free(pimg->pal);
e4b8154a 69 delete pimg;
464122b6
JS
70 pimg = paux;
71 }
9742d3cc
GRG
72
73 m_pimage = NULL;
74 m_pfirst = NULL;
75 m_plast = NULL;
76 m_image = 0;
77 m_nimages = 0;
464122b6
JS
78}
79
80
81//---------------------------------------------------------------------------
82// Convert this image to a wxImage object
83//---------------------------------------------------------------------------
84
85// This function was designed by Vaclav Slavik
86
87bool wxGIFDecoder::ConvertToImage(wxImage *image) const
88{
89 unsigned char *src, *dst, *pal;
90 unsigned long i;
91 int transparent;
92
3c87527e
GRG
93 /* just in case... */
94 image->Destroy();
95
464122b6
JS
96 /* create the image */
97 image->Create(GetWidth(), GetHeight());
98
99 if (!image->Ok())
100 return FALSE;
101
102 pal = GetPalette();
103 src = GetData();
104 dst = image->GetData();
105 transparent = GetTransparentColour();
106
107 /* set transparent colour mask */
108 if (transparent != -1)
109 {
110 for (i = 0; i < 256; i++)
111 {
112 if ((pal[3 * i + 0] == 255) &&
113 (pal[3 * i + 1] == 0) &&
114 (pal[3 * i + 2] == 255))
115 {
116 pal[3 * i + 2] = 254;
117 }
118 }
119
120 pal[3 * transparent + 0] = 255,
121 pal[3 * transparent + 1] = 0,
122 pal[3 * transparent + 2] = 255;
123
124 image->SetMaskColour(255, 0, 255);
125 }
126 else
127 image->SetMask(FALSE);
128
129 /* copy image data */
130 for (i = 0; i < (GetWidth() * GetHeight()); i++, src++)
131 {
132 *(dst++) = pal[3 * (*src) + 0];
133 *(dst++) = pal[3 * (*src) + 1];
134 *(dst++) = pal[3 * (*src) + 2];
135 }
136
137 return TRUE;
138}
139
2ce0a6e2 140
464122b6
JS
141//---------------------------------------------------------------------------
142// Data accessors
143//---------------------------------------------------------------------------
144
145// Get data for current frame
146
147int wxGIFDecoder::GetFrameIndex() const { return m_image; }
148unsigned char* wxGIFDecoder::GetData() const { return (m_pimage->p); }
149unsigned char* wxGIFDecoder::GetPalette() const { return (m_pimage->pal); }
150unsigned int wxGIFDecoder::GetWidth() const { return (m_pimage->w); }
151unsigned int wxGIFDecoder::GetHeight() const { return (m_pimage->h); }
152unsigned int wxGIFDecoder::GetTop() const { return (m_pimage->top); }
153unsigned int wxGIFDecoder::GetLeft() const { return (m_pimage->left); }
154int wxGIFDecoder::GetTransparentColour() const { return (m_pimage->transparent); }
155int wxGIFDecoder::GetDisposalMethod() const { return (m_pimage->disposal); }
156long wxGIFDecoder::GetDelay() const { return (m_pimage->delay); }
157
158// Get global data
159
160unsigned int wxGIFDecoder::GetLogicalScreenWidth() const { return m_screenw; }
161unsigned int wxGIFDecoder::GetLogicalScreenHeight() const { return m_screenh; }
162int wxGIFDecoder::GetBackgroundColour() const { return m_background; }
163int wxGIFDecoder::GetNumberOfFrames() const { return m_nimages; }
164bool wxGIFDecoder::IsAnimation() const { return (m_nimages > 1); }
165
166
167//---------------------------------------------------------------------------
168// Functions to move through the animation
169//---------------------------------------------------------------------------
170
171bool wxGIFDecoder::GoFirstFrame()
172{
173 if (!IsAnimation())
174 return FALSE;
175
176 m_image = 1;
177 m_pimage = m_pfirst;
178 return TRUE;
179}
180
181bool wxGIFDecoder::GoLastFrame()
182{
183 if (!IsAnimation())
184 return FALSE;
185
186 m_image = m_nimages;
187 m_pimage = m_plast;
188 return TRUE;
189}
190
191bool wxGIFDecoder::GoNextFrame(bool cyclic)
192{
193 if (!IsAnimation())
194 return FALSE;
195
196 if ((m_image < m_nimages) || (cyclic))
197 {
198 m_pimage = m_pimage->next;
199 m_image++;
200
201 if (!m_pimage)
202 {
203 m_image = 1;
204 m_pimage = m_pfirst;
205 }
206
207 return TRUE;
208 }
209 else
210 return FALSE;
2ce0a6e2 211}
464122b6
JS
212
213bool wxGIFDecoder::GoPrevFrame(bool cyclic)
214{
215 if (!IsAnimation())
216 return FALSE;
217
218 if ((m_image > 1) || (cyclic))
219 {
220 m_pimage = m_pimage->prev;
221 m_image--;
222
223 if (!m_pimage)
224 {
225 m_image = m_nimages;
226 m_pimage = m_plast;
227 }
228
229 return TRUE;
230 }
231 else
232 return FALSE;
233}
234
235bool wxGIFDecoder::GoFrame(int which)
236{
237 int i;
238
239 if (!IsAnimation())
240 return FALSE;
241
242 if ((which >= 1) && (which <= m_nimages))
243 {
244 m_pimage = m_pfirst;
245
246 for (i = 1; i < which; i++)
247 m_pimage = m_pimage->next;
248
249 return TRUE;
250 }
251 else
252 return FALSE;
253}
254
255
256//---------------------------------------------------------------------------
257// GIF reading and decoding
258//---------------------------------------------------------------------------
259
260// getcode:
261// Reads the next code from the file stream, with size 'bits'
262//
263int wxGIFDecoder::getcode(int bits, int ab_fin)
264{
265 unsigned int mask; /* bit mask */
266 unsigned int code; /* code (result) */
267
268
269 /* get remaining bits from last byte read */
270 mask = (1 << bits) - 1;
271 code = (m_lastbyte >> (8 - m_restbits)) & mask;
272
273 /* keep reading new bytes while needed */
274 while (bits > m_restbits)
275 {
276 /* if no bytes left in this block, read the next block */
277 if (m_restbyte == 0)
278 {
279 m_restbyte = (unsigned char)m_f->GetC();
280
281 /* Some encoders are a bit broken: instead of issuing
282 * an end-of-image symbol (ab_fin) they come up with
283 * a zero-length subblock!! We catch this here so
284 * that the decoder sees an ab_fin code.
285 */
286 if (m_restbyte == 0)
287 {
288 code = ab_fin;
289 break;
290 }
8708a10f
GRG
291
292 /* prefetch data */
293 m_f->Read((void *) m_buffer, m_restbyte);
294 m_bufp = m_buffer;
464122b6
JS
295 }
296
297 /* read next byte and isolate the bits we need */
8708a10f 298 m_lastbyte = (unsigned char) (*m_bufp++);
464122b6
JS
299 mask = (1 << (bits - m_restbits)) - 1;
300 code = code + ((m_lastbyte & mask) << m_restbits);
301 m_restbyte--;
302
303 /* adjust total number of bits extracted from the buffer */
304 m_restbits = m_restbits + 8;
305 }
2ce0a6e2 306
464122b6
JS
307 /* find number of bits remaining for next code */
308 m_restbits = (m_restbits - bits);
309
310 return code;
311}
312
313
314// dgif:
315// GIF decoding function. The initial code size (aka root size)
316// is 'bits'. Supports interlaced images (interl == 1).
317//
e4b8154a 318int wxGIFDecoder::dgif(GIFImage *img, int interl, int bits)
464122b6
JS
319{
320 int ab_prefix[4096]; /* alphabet (prefixes) */
321 int ab_tail[4096]; /* alphabet (tails) */
322 int stack[4096]; /* decompression stack */
323
324 int ab_clr; /* clear code */
325 int ab_fin; /* end of info code */
326 int ab_bits; /* actual symbol width, in bits */
327 int ab_free; /* first free position in alphabet */
328 int ab_max; /* last possible character in alphabet */
329 int pass; /* pass number in interlaced images */
330 int pos; /* index into decompresion stack */
331 unsigned int x, y; /* position in image buffer */
332
333 int code, readcode, lastcode, abcabca;
334
335 /* these won't change */
336 ab_clr = (1 << bits);
337 ab_fin = (1 << bits) + 1;
338
339 /* these will change through the decompression proccess */
340 ab_bits = bits + 1;
341 ab_free = (1 << bits) + 2;
342 ab_max = (1 << ab_bits) - 1;
343 lastcode = -1;
344 abcabca = -1;
345 pass = 1;
346 pos = x = y = 0;
347
8708a10f 348 /* reset decoder vars */
464122b6
JS
349 m_restbits = 0;
350 m_restbyte = 0;
351 m_lastbyte = 0;
352
353 do
354 {
355 /* get next code */
356 readcode = code = getcode(ab_bits, ab_fin);
357
358 /* end of image? */
359 if (code == ab_fin) break;
360
361 /* reset alphabet? */
362 if (code == ab_clr)
363 {
364 /* reset main variables */
365 ab_bits = bits + 1;
366 ab_free = (1 << bits) + 2;
367 ab_max = (1 << ab_bits) - 1;
368 lastcode = -1;
369 abcabca = -1;
370
371 /* skip to next code */
372 continue;
373 }
374
375 /* unknown code: special case (like in ABCABCA) */
376 if (code >= ab_free)
377 {
378 code = lastcode; /* take last string */
379 stack[pos++] = abcabca; /* add first character */
380 }
381
382 /* build the string for this code in the stack */
383 while (code > ab_clr)
384 {
385 stack[pos++] = ab_tail[code];
386 code = ab_prefix[code];
387 }
388 stack[pos] = code; /* push last code into the stack */
389 abcabca = code; /* save for special case */
390
391 /* make new entry in alphabet (only if NOT just cleared) */
392 if (lastcode != -1)
393 {
394 ab_prefix[ab_free] = lastcode;
395 ab_tail[ab_free] = code;
396 ab_free++;
397
398 if ((ab_free > ab_max) && (ab_bits < 12))
399 {
400 ab_bits++;
401 ab_max = (1 << ab_bits) - 1;
402 }
403 }
404
405 /* dump stack data to the buffer */
406 while (pos >= 0)
407 {
408 (img->p)[x + (y * (img->w))] = (char)stack[pos--];
409
410 if (++x >= (img->w))
411 {
412 x = 0;
413
414 if (interl)
415 {
416 /* support for interlaced images */
417 switch (pass)
418 {
419 case 1: y += 8; break;
420 case 2: y += 8; break;
421 case 3: y += 4; break;
422 case 4: y += 2; break;
423 }
424 if (y >= (img->h))
425 {
426 switch (++pass)
427 {
428 case 2: y = 4; break;
429 case 3: y = 2; break;
430 case 4: y = 1; break;
431 }
432 }
433 }
434 else
435 {
436 /* non-interlaced */
437 y++;
438 }
439 }
440 }
441
442 pos = 0;
443 lastcode = readcode;
444 }
445 while (code != ab_fin);
446
447 return 0;
448}
449
450
3c87527e
GRG
451// CanRead:
452// Returns TRUE if the file looks like a valid GIF, FALSE otherwise.
453//
454bool wxGIFDecoder::CanRead()
455{
456 unsigned char buf[3];
457
3c87527e 458 m_f->Read(buf, 3);
700ec454 459 m_f->SeekI(-3, wxFromCurrent);
3c87527e
GRG
460
461 return (memcmp(buf, "GIF", 3) == 0);
462}
463
464
464122b6
JS
465// ReadGIF:
466// Reads and decodes one or more GIF images, depending on whether
467// animated GIF support is enabled. Can read GIFs with any bit
468// size (color depth), but the output images are always expanded
469// to 8 bits per pixel. Also, the image palettes always contain
8141573c 470// 256 colors, although some of them may be unused. Returns wxGIF_OK
e4b8154a
GRG
471// (== 0) on success, or an error code if something fails (see
472// header file for details)
464122b6
JS
473//
474int wxGIFDecoder::ReadGIF()
475{
476 int ncolors, bits, interl, transparent, disposal, i;
477 long size;
478 long delay;
479 unsigned char type;
480 unsigned char pal[768];
481 unsigned char buf[16];
e4b8154a 482 GIFImage **ppimg, *pimg, *pprev;
464122b6 483
3c87527e
GRG
484 /* check GIF signature */
485 if (!CanRead())
e4b8154a 486 return wxGIF_INVFORMAT;
464122b6 487
8141573c 488 /* check for animated GIF support (ver. >= 89a) */
464122b6
JS
489 m_f->Read(buf, 6);
490
464122b6
JS
491 if (memcmp(buf + 3, "89a", 3) < 0)
492 m_anim = FALSE;
493
494 /* read logical screen descriptor block (LSDB) */
495 m_f->Read(buf, 7);
496 m_screenw = buf[0] + 256 * buf[1];
497 m_screenh = buf[2] + 256 * buf[3];
498
499 /* load global color map if available */
500 if ((buf[4] & 0x80) == 0x80)
501 {
502 m_background = buf[5];
503
504 ncolors = 2 << (buf[4] & 0x07);
505 m_f->Read(pal, 3 * ncolors);
506 }
507
508 /* transparent colour, disposal method and delay default to unused */
509 transparent = -1;
510 disposal = -1;
511 delay = -1;
512
513 /* read images */
514 ppimg = &m_pfirst;
515 pprev = NULL;
516 pimg = NULL;
517
8141573c
GRG
518 bool done = FALSE;
519
520 while(!done)
464122b6
JS
521 {
522 type = (unsigned char)m_f->GetC();
523
524 /* end of data? */
525 if (type == 0x3B)
8141573c
GRG
526 {
527 done = TRUE;
528 }
529 else
464122b6
JS
530 /* extension block? */
531 if (type == 0x21)
532 {
533 if (((unsigned char)m_f->GetC()) == 0xF9)
534 /* graphics control extension, parse it */
535 {
536 m_f->Read(buf, 6);
537
538 /* read delay and convert from 1/100 of a second to ms */
539 delay = 10 * (buf[2] + 256 * buf[3]);
540
541 /* read transparent colour index, if used */
542 if (buf[1] & 0x01)
543 transparent = buf[4];
544
545 /* read disposal method */
546 disposal = (buf[1] & 0x1C) - 1;
547 }
548 else
549 /* other extension, skip */
2ce0a6e2 550 {
464122b6
JS
551 while ((i = (unsigned char)m_f->GetC()) != 0)
552 {
464122b6
JS
553 m_f->SeekI(i, wxFromCurrent);
554 }
555 }
556 }
8141573c 557 else
464122b6
JS
558 /* image descriptor block? */
559 if (type == 0x2C)
560 {
561 /* allocate memory for IMAGEN struct */
e4b8154a 562 pimg = (*ppimg) = new GIFImage();
464122b6
JS
563
564 if (pimg == NULL)
565 {
566 Destroy();
e4b8154a 567 return wxGIF_MEMERR;
464122b6
JS
568 }
569
570 /* fill in the data */
571 m_f->Read(buf, 9);
572 pimg->left = buf[4] + 256 * buf[5];
573 pimg->top = buf[4] + 256 * buf[5];
574 pimg->w = buf[4] + 256 * buf[5];
575 pimg->h = buf[6] + 256 * buf[7];
576 interl = ((buf[8] & 0x40)? 1 : 0);
577 size = pimg->w * pimg->h;
578
579 pimg->transparent = transparent;
580 pimg->disposal = disposal;
581 pimg->delay = delay;
582 pimg->next = NULL;
583 pimg->prev = pprev;
584 pprev = pimg;
585 ppimg = &pimg->next;
586
587 /* allocate memory for image and palette */
13111b2a 588 pimg->p = (unsigned char *) malloc((size_t)size);
464122b6
JS
589 pimg->pal = (unsigned char *) malloc(768);
590
591 if ((!pimg->p) || (!pimg->pal))
592 {
593 Destroy();
e4b8154a 594 return wxGIF_MEMERR;
464122b6
JS
595 }
596
597 /* load local color map if available, else use global map */
598 if ((buf[8] & 0x80) == 0x80)
599 {
600 ncolors = 2 << (buf[8] & 0x07);
601 m_f->Read(pimg->pal, 3 * ncolors);
602 }
603 else
604 memcpy(pimg->pal, pal, 768);
605
606 /* get initial code size from first byte in raster data */
607 bits = (unsigned char)m_f->GetC();
608
609 /* decode image */
610 dgif(pimg, interl, bits);
464122b6 611 m_nimages++;
464122b6 612
8141573c
GRG
613 /* if this is not an animated GIF, exit after first image */
614 if (!m_anim)
615 done = TRUE;
616 }
464122b6
JS
617 }
618
8141573c 619 /* setup image pointers */
464122b6
JS
620 if (m_nimages != 0)
621 {
622 m_image = 1;
623 m_plast = pimg;
624 m_pimage = m_pfirst;
625 }
626
8141573c
GRG
627 /* try to read to the end of the stream */
628 while (type != 0x3B)
629 {
630 type = (unsigned char)m_f->GetC();
631
632 if (type == 0x21)
633 {
634 /* extension type */
635 (void) m_f->GetC();
636
637 /* skip all data */
638 while ((i = (unsigned char)m_f->GetC()) != 0)
639 {
640 m_f->SeekI(i, wxFromCurrent);
641 }
642 }
643 else if (type == 0x2C)
644 {
645 /* image descriptor block */
646 m_f->Read(buf, 9);
647
648 /* local color map */
649 if ((buf[8] & 0x80) == 0x80)
650 {
651 ncolors = 2 << (buf[8] & 0x07);
9742d3cc 652 m_f->SeekI(3 * ncolors, wxFromCurrent);
8141573c
GRG
653 }
654
655 /* initial code size */
656 (void) m_f->GetC();
657
658 /* skip all data */
659 while ((i = (unsigned char)m_f->GetC()) != 0)
660 {
661 m_f->SeekI(i, wxFromCurrent);
662 }
663 }
9742d3cc 664 else if ((type != 0x3B) && (type != 00)) /* testing */
8141573c
GRG
665 {
666 /* images are OK, but couldn't read to the end of the stream */
667 return wxGIF_TRUNCATED;
668 }
669 }
670
e4b8154a 671 return wxGIF_OK;
464122b6
JS
672}
673
7be110e3 674#endif // wxUSE_STREAMS && wxUSE_GIF