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