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