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