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