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