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