]> git.saurik.com Git - wxWidgets.git/blame - src/common/gifdecod.cpp
tmake template for DLL project for VC++ 6.0
[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>
5b4f8dd5
GRG
5// Version: 3.03
6// RCS-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
JS
30#include "wx/gifdecod.h"
31
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
134
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;
205}
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 }
296
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];
5b4f8dd5 447 off_t pos;
3c87527e 448
5b4f8dd5 449 pos = m_f->TellI();
3c87527e
GRG
450 m_f->SeekI(0, wxFromStart);
451 m_f->Read(buf, 3);
5b4f8dd5 452 m_f->SeekI(pos, wxFromStart);
3c87527e
GRG
453
454 return (memcmp(buf, "GIF", 3) == 0);
455}
456
457
464122b6
JS
458// ReadGIF:
459// Reads and decodes one or more GIF images, depending on whether
460// animated GIF support is enabled. Can read GIFs with any bit
461// size (color depth), but the output images are always expanded
462// to 8 bits per pixel. Also, the image palettes always contain
463// 256 colors, although some of them may be unused. Returns E_OK
464// (== 0) on success, or an error code if something fails. Error
465// codes are E_ARCHIVO, E_FORMATO, E_MEMORIA (see header file).
466//
467int wxGIFDecoder::ReadGIF()
468{
469 int ncolors, bits, interl, transparent, disposal, i;
470 long size;
471 long delay;
472 unsigned char type;
473 unsigned char pal[768];
474 unsigned char buf[16];
475 IMAGEN **ppimg, *pimg, *pprev;
476
3c87527e
GRG
477 /* check GIF signature */
478 if (!CanRead())
479 return E_FORMATO;
464122b6 480
3c87527e
GRG
481 /* check for and animated GIF support (ver. >= 89a) */
482 m_f->SeekI(0, wxFromStart);
464122b6
JS
483 m_f->Read(buf, 6);
484
464122b6
JS
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 while (1)
513 {
514 type = (unsigned char)m_f->GetC();
515
516 /* end of data? */
517 if (type == 0x3B)
518 break;
519
520 /* extension block? */
521 if (type == 0x21)
522 {
523 if (((unsigned char)m_f->GetC()) == 0xF9)
524 /* graphics control extension, parse it */
525 {
526 m_f->Read(buf, 6);
527
528 /* read delay and convert from 1/100 of a second to ms */
529 delay = 10 * (buf[2] + 256 * buf[3]);
530
531 /* read transparent colour index, if used */
532 if (buf[1] & 0x01)
533 transparent = buf[4];
534
535 /* read disposal method */
536 disposal = (buf[1] & 0x1C) - 1;
537 }
538 else
539 /* other extension, skip */
540 {
541 while ((i = (unsigned char)m_f->GetC()) != 0)
542 {
543 /* This line should not be neccessary!
544 * Some images are not loaded correctly
545 * without it. A bug in wxStream?
5b4f8dd5 546 * Yes. Fixed now.
464122b6
JS
547 */
548 // m_f->SeekI(m_f->TellI(), wxFromStart);
5b4f8dd5 549
464122b6
JS
550 m_f->SeekI(i, wxFromCurrent);
551 }
552 }
553 }
554
555 /* image descriptor block? */
556 if (type == 0x2C)
557 {
558 /* allocate memory for IMAGEN struct */
559 pimg = (*ppimg) = (IMAGEN *) malloc(sizeof(IMAGEN));
560
561 if (pimg == NULL)
562 {
563 Destroy();
564 return E_MEMORIA;
565 }
566
567 /* fill in the data */
568 m_f->Read(buf, 9);
569 pimg->left = buf[4] + 256 * buf[5];
570 pimg->top = buf[4] + 256 * buf[5];
571 pimg->w = buf[4] + 256 * buf[5];
572 pimg->h = buf[6] + 256 * buf[7];
573 interl = ((buf[8] & 0x40)? 1 : 0);
574 size = pimg->w * pimg->h;
575
576 pimg->transparent = transparent;
577 pimg->disposal = disposal;
578 pimg->delay = delay;
579 pimg->next = NULL;
580 pimg->prev = pprev;
581 pprev = pimg;
582 ppimg = &pimg->next;
583
584 /* allocate memory for image and palette */
585 pimg->p = (unsigned char *) malloc(size);
586 pimg->pal = (unsigned char *) malloc(768);
587
588 if ((!pimg->p) || (!pimg->pal))
589 {
590 Destroy();
591 return E_MEMORIA;
592 }
593
594 /* load local color map if available, else use global map */
595 if ((buf[8] & 0x80) == 0x80)
596 {
597 ncolors = 2 << (buf[8] & 0x07);
598 m_f->Read(pimg->pal, 3 * ncolors);
599 }
600 else
601 memcpy(pimg->pal, pal, 768);
602
603 /* get initial code size from first byte in raster data */
604 bits = (unsigned char)m_f->GetC();
605
606 /* decode image */
607 dgif(pimg, interl, bits);
608
609 m_nimages++;
610 }
611
612 /* if we have one image and no animated GIF support, exit */
613 if (m_nimages == 1 && !m_anim)
614 break;
615 }
616
617 /* finish successfully :-) */
618 if (m_nimages != 0)
619 {
620 m_image = 1;
621 m_plast = pimg;
622 m_pimage = m_pfirst;
623 }
624
625 return E_OK;
626}
627
7be110e3 628#endif // wxUSE_STREAMS && wxUSE_GIF