]> git.saurik.com Git - wxWidgets.git/blame - src/common/gifdecod.cpp
Various small fixes and tweaks
[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{
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
53wxGIFDecoder::~wxGIFDecoder()
54{
55 Destroy();
56}
57
58void wxGIFDecoder::Destroy()
59{
60 IMAGEN *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 free(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
81bool wxGIFDecoder::ConvertToImage(wxImage *image) const
82{
83 unsigned char *src, *dst, *pal;
84 unsigned long i;
85 int transparent;
86
3c87527e
GRG
87 /* just in case... */
88 image->Destroy();
89
464122b6
JS
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
2ce0a6e2 134
464122b6
JS
135//---------------------------------------------------------------------------
136// Data accessors
137//---------------------------------------------------------------------------
138
139// Get data for current frame
140
141int wxGIFDecoder::GetFrameIndex() const { return m_image; }
142unsigned char* wxGIFDecoder::GetData() const { return (m_pimage->p); }
143unsigned char* wxGIFDecoder::GetPalette() const { return (m_pimage->pal); }
144unsigned int wxGIFDecoder::GetWidth() const { return (m_pimage->w); }
145unsigned int wxGIFDecoder::GetHeight() const { return (m_pimage->h); }
146unsigned int wxGIFDecoder::GetTop() const { return (m_pimage->top); }
147unsigned int wxGIFDecoder::GetLeft() const { return (m_pimage->left); }
148int wxGIFDecoder::GetTransparentColour() const { return (m_pimage->transparent); }
149int wxGIFDecoder::GetDisposalMethod() const { return (m_pimage->disposal); }
150long wxGIFDecoder::GetDelay() const { return (m_pimage->delay); }
151
152// Get global data
153
154unsigned int wxGIFDecoder::GetLogicalScreenWidth() const { return m_screenw; }
155unsigned int wxGIFDecoder::GetLogicalScreenHeight() const { return m_screenh; }
156int wxGIFDecoder::GetBackgroundColour() const { return m_background; }
157int wxGIFDecoder::GetNumberOfFrames() const { return m_nimages; }
158bool wxGIFDecoder::IsAnimation() const { return (m_nimages > 1); }
159
160
161//---------------------------------------------------------------------------
162// Functions to move through the animation
163//---------------------------------------------------------------------------
164
165bool wxGIFDecoder::GoFirstFrame()
166{
167 if (!IsAnimation())
168 return FALSE;
169
170 m_image = 1;
171 m_pimage = m_pfirst;
172 return TRUE;
173}
174
175bool 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
185bool 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;
2ce0a6e2 205}
464122b6
JS
206
207bool 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
229bool 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//
257int 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
287 /* read next byte and isolate the bits we need */
288 m_lastbyte = (unsigned char)m_f->GetC();
289 mask = (1 << (bits - m_restbits)) - 1;
290 code = code + ((m_lastbyte & mask) << m_restbits);
291 m_restbyte--;
292
293 /* adjust total number of bits extracted from the buffer */
294 m_restbits = m_restbits + 8;
295 }
2ce0a6e2 296
464122b6
JS
297 /* find number of bits remaining for next code */
298 m_restbits = (m_restbits - bits);
299
300 return code;
301}
302
303
304// dgif:
305// GIF decoding function. The initial code size (aka root size)
306// is 'bits'. Supports interlaced images (interl == 1).
307//
308int wxGIFDecoder::dgif(IMAGEN *img, int interl, int bits)
309{
310 int ab_prefix[4096]; /* alphabet (prefixes) */
311 int ab_tail[4096]; /* alphabet (tails) */
312 int stack[4096]; /* decompression stack */
313
314 int ab_clr; /* clear code */
315 int ab_fin; /* end of info code */
316 int ab_bits; /* actual symbol width, in bits */
317 int ab_free; /* first free position in alphabet */
318 int ab_max; /* last possible character in alphabet */
319 int pass; /* pass number in interlaced images */
320 int pos; /* index into decompresion stack */
321 unsigned int x, y; /* position in image buffer */
322
323 int code, readcode, lastcode, abcabca;
324
325 /* these won't change */
326 ab_clr = (1 << bits);
327 ab_fin = (1 << bits) + 1;
328
329 /* these will change through the decompression proccess */
330 ab_bits = bits + 1;
331 ab_free = (1 << bits) + 2;
332 ab_max = (1 << ab_bits) - 1;
333 lastcode = -1;
334 abcabca = -1;
335 pass = 1;
336 pos = x = y = 0;
337
338 /* reset static globals */
339 m_restbits = 0;
340 m_restbyte = 0;
341 m_lastbyte = 0;
342
343 do
344 {
345 /* get next code */
346 readcode = code = getcode(ab_bits, ab_fin);
347
348 /* end of image? */
349 if (code == ab_fin) break;
350
351 /* reset alphabet? */
352 if (code == ab_clr)
353 {
354 /* reset main variables */
355 ab_bits = bits + 1;
356 ab_free = (1 << bits) + 2;
357 ab_max = (1 << ab_bits) - 1;
358 lastcode = -1;
359 abcabca = -1;
360
361 /* skip to next code */
362 continue;
363 }
364
365 /* unknown code: special case (like in ABCABCA) */
366 if (code >= ab_free)
367 {
368 code = lastcode; /* take last string */
369 stack[pos++] = abcabca; /* add first character */
370 }
371
372 /* build the string for this code in the stack */
373 while (code > ab_clr)
374 {
375 stack[pos++] = ab_tail[code];
376 code = ab_prefix[code];
377 }
378 stack[pos] = code; /* push last code into the stack */
379 abcabca = code; /* save for special case */
380
381 /* make new entry in alphabet (only if NOT just cleared) */
382 if (lastcode != -1)
383 {
384 ab_prefix[ab_free] = lastcode;
385 ab_tail[ab_free] = code;
386 ab_free++;
387
388 if ((ab_free > ab_max) && (ab_bits < 12))
389 {
390 ab_bits++;
391 ab_max = (1 << ab_bits) - 1;
392 }
393 }
394
395 /* dump stack data to the buffer */
396 while (pos >= 0)
397 {
398 (img->p)[x + (y * (img->w))] = (char)stack[pos--];
399
400 if (++x >= (img->w))
401 {
402 x = 0;
403
404 if (interl)
405 {
406 /* support for interlaced images */
407 switch (pass)
408 {
409 case 1: y += 8; break;
410 case 2: y += 8; break;
411 case 3: y += 4; break;
412 case 4: y += 2; break;
413 }
414 if (y >= (img->h))
415 {
416 switch (++pass)
417 {
418 case 2: y = 4; break;
419 case 3: y = 2; break;
420 case 4: y = 1; break;
421 }
422 }
423 }
424 else
425 {
426 /* non-interlaced */
427 y++;
428 }
429 }
430 }
431
432 pos = 0;
433 lastcode = readcode;
434 }
435 while (code != ab_fin);
436
437 return 0;
438}
439
440
3c87527e
GRG
441// CanRead:
442// Returns TRUE if the file looks like a valid GIF, FALSE otherwise.
443//
444bool wxGIFDecoder::CanRead()
445{
446 unsigned char buf[3];
447
3c87527e 448 m_f->Read(buf, 3);
700ec454 449 m_f->SeekI(-3, wxFromCurrent);
3c87527e
GRG
450
451 return (memcmp(buf, "GIF", 3) == 0);
452}
453
454
464122b6
JS
455// ReadGIF:
456// Reads and decodes one or more GIF images, depending on whether
457// animated GIF support is enabled. Can read GIFs with any bit
458// size (color depth), but the output images are always expanded
459// to 8 bits per pixel. Also, the image palettes always contain
460// 256 colors, although some of them may be unused. Returns E_OK
461// (== 0) on success, or an error code if something fails. Error
462// codes are E_ARCHIVO, E_FORMATO, E_MEMORIA (see header file).
463//
464int wxGIFDecoder::ReadGIF()
465{
466 int ncolors, bits, interl, transparent, disposal, i;
467 long size;
468 long delay;
469 unsigned char type;
470 unsigned char pal[768];
471 unsigned char buf[16];
472 IMAGEN **ppimg, *pimg, *pprev;
473
3c87527e
GRG
474 /* check GIF signature */
475 if (!CanRead())
476 return E_FORMATO;
464122b6 477
3c87527e 478 /* check for and animated GIF support (ver. >= 89a) */
464122b6
JS
479 m_f->Read(buf, 6);
480
464122b6
JS
481 if (memcmp(buf + 3, "89a", 3) < 0)
482 m_anim = FALSE;
483
484 /* read logical screen descriptor block (LSDB) */
485 m_f->Read(buf, 7);
486 m_screenw = buf[0] + 256 * buf[1];
487 m_screenh = buf[2] + 256 * buf[3];
488
489 /* load global color map if available */
490 if ((buf[4] & 0x80) == 0x80)
491 {
492 m_background = buf[5];
493
494 ncolors = 2 << (buf[4] & 0x07);
495 m_f->Read(pal, 3 * ncolors);
496 }
497
498 /* transparent colour, disposal method and delay default to unused */
499 transparent = -1;
500 disposal = -1;
501 delay = -1;
502
503 /* read images */
504 ppimg = &m_pfirst;
505 pprev = NULL;
506 pimg = NULL;
507
2ce0a6e2
DW
508#if defined(__VISAGECPP__)
509// VA just can't stand while(1)
510 bool bOs2var = TRUE;
511 while(bOs2var)
512#else
464122b6 513 while (1)
2ce0a6e2 514#endif
464122b6
JS
515 {
516 type = (unsigned char)m_f->GetC();
517
518 /* end of data? */
519 if (type == 0x3B)
520 break;
521
522 /* extension block? */
523 if (type == 0x21)
524 {
525 if (((unsigned char)m_f->GetC()) == 0xF9)
526 /* graphics control extension, parse it */
527 {
528 m_f->Read(buf, 6);
529
530 /* read delay and convert from 1/100 of a second to ms */
531 delay = 10 * (buf[2] + 256 * buf[3]);
532
533 /* read transparent colour index, if used */
534 if (buf[1] & 0x01)
535 transparent = buf[4];
536
537 /* read disposal method */
538 disposal = (buf[1] & 0x1C) - 1;
539 }
540 else
541 /* other extension, skip */
2ce0a6e2 542 {
464122b6
JS
543 while ((i = (unsigned char)m_f->GetC()) != 0)
544 {
545 /* This line should not be neccessary!
546 * Some images are not loaded correctly
547 * without it. A bug in wxStream?
5b4f8dd5 548 * Yes. Fixed now.
464122b6
JS
549 */
550 // m_f->SeekI(m_f->TellI(), wxFromStart);
5b4f8dd5 551
464122b6
JS
552 m_f->SeekI(i, wxFromCurrent);
553 }
554 }
555 }
556
557 /* image descriptor block? */
558 if (type == 0x2C)
559 {
560 /* allocate memory for IMAGEN struct */
561 pimg = (*ppimg) = (IMAGEN *) malloc(sizeof(IMAGEN));
562
563 if (pimg == NULL)
564 {
565 Destroy();
566 return E_MEMORIA;
567 }
568
569 /* fill in the data */
570 m_f->Read(buf, 9);
571 pimg->left = buf[4] + 256 * buf[5];
572 pimg->top = buf[4] + 256 * buf[5];
573 pimg->w = buf[4] + 256 * buf[5];
574 pimg->h = buf[6] + 256 * buf[7];
575 interl = ((buf[8] & 0x40)? 1 : 0);
576 size = pimg->w * pimg->h;
577
578 pimg->transparent = transparent;
579 pimg->disposal = disposal;
580 pimg->delay = delay;
581 pimg->next = NULL;
582 pimg->prev = pprev;
583 pprev = pimg;
584 ppimg = &pimg->next;
585
586 /* allocate memory for image and palette */
587 pimg->p = (unsigned char *) malloc(size);
588 pimg->pal = (unsigned char *) malloc(768);
589
590 if ((!pimg->p) || (!pimg->pal))
591 {
592 Destroy();
593 return E_MEMORIA;
594 }
595
596 /* load local color map if available, else use global map */
597 if ((buf[8] & 0x80) == 0x80)
598 {
599 ncolors = 2 << (buf[8] & 0x07);
600 m_f->Read(pimg->pal, 3 * ncolors);
601 }
602 else
603 memcpy(pimg->pal, pal, 768);
604
605 /* get initial code size from first byte in raster data */
606 bits = (unsigned char)m_f->GetC();
607
608 /* decode image */
609 dgif(pimg, interl, bits);
610
611 m_nimages++;
612 }
613
614 /* if we have one image and no animated GIF support, exit */
615 if (m_nimages == 1 && !m_anim)
616 break;
617 }
618
619 /* finish successfully :-) */
620 if (m_nimages != 0)
621 {
622 m_image = 1;
623 m_plast = pimg;
624 m_pimage = m_pfirst;
625 }
626
627 return E_OK;
628}
629
7be110e3 630#endif // wxUSE_STREAMS && wxUSE_GIF