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