]> git.saurik.com Git - wxWidgets.git/blame - src/common/gifdecod.cpp
Added wxFontEnumerator class for wxMSW, and fixed text validator for French
[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
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
38wxGIFDecoder::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
54wxGIFDecoder::~wxGIFDecoder()
55{
56 Destroy();
57}
58
59void 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
82bool wxGIFDecoder::ConvertToImage(wxImage *image) const
83{
84 unsigned char *src, *dst, *pal;
85 unsigned long i;
86 int transparent;
87
3c87527e
GRG
88 /* just in case... */
89 image->Destroy();
90
464122b6
JS
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
142int wxGIFDecoder::GetFrameIndex() const { return m_image; }
143unsigned char* wxGIFDecoder::GetData() const { return (m_pimage->p); }
144unsigned char* wxGIFDecoder::GetPalette() const { return (m_pimage->pal); }
145unsigned int wxGIFDecoder::GetWidth() const { return (m_pimage->w); }
146unsigned int wxGIFDecoder::GetHeight() const { return (m_pimage->h); }
147unsigned int wxGIFDecoder::GetTop() const { return (m_pimage->top); }
148unsigned int wxGIFDecoder::GetLeft() const { return (m_pimage->left); }
149int wxGIFDecoder::GetTransparentColour() const { return (m_pimage->transparent); }
150int wxGIFDecoder::GetDisposalMethod() const { return (m_pimage->disposal); }
151long wxGIFDecoder::GetDelay() const { return (m_pimage->delay); }
152
153// Get global data
154
155unsigned int wxGIFDecoder::GetLogicalScreenWidth() const { return m_screenw; }
156unsigned int wxGIFDecoder::GetLogicalScreenHeight() const { return m_screenh; }
157int wxGIFDecoder::GetBackgroundColour() const { return m_background; }
158int wxGIFDecoder::GetNumberOfFrames() const { return m_nimages; }
159bool wxGIFDecoder::IsAnimation() const { return (m_nimages > 1); }
160
161
162//---------------------------------------------------------------------------
163// Functions to move through the animation
164//---------------------------------------------------------------------------
165
166bool wxGIFDecoder::GoFirstFrame()
167{
168 if (!IsAnimation())
169 return FALSE;
170
171 m_image = 1;
172 m_pimage = m_pfirst;
173 return TRUE;
174}
175
176bool 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
186bool 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
208bool 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
230bool 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//
258int 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//
309int 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
3c87527e
GRG
442// CanRead:
443// Returns TRUE if the file looks like a valid GIF, FALSE otherwise.
444//
445bool wxGIFDecoder::CanRead()
446{
447 unsigned char buf[3];
5b4f8dd5 448 off_t pos;
3c87527e 449
5b4f8dd5 450 pos = m_f->TellI();
3c87527e
GRG
451 m_f->SeekI(0, wxFromStart);
452 m_f->Read(buf, 3);
5b4f8dd5 453 m_f->SeekI(pos, wxFromStart);
3c87527e
GRG
454
455 return (memcmp(buf, "GIF", 3) == 0);
456}
457
458
464122b6
JS
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 E_OK
465// (== 0) on success, or an error code if something fails. Error
466// codes are E_ARCHIVO, E_FORMATO, E_MEMORIA (see header file).
467//
468int 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 IMAGEN **ppimg, *pimg, *pprev;
477
3c87527e
GRG
478 /* check GIF signature */
479 if (!CanRead())
480 return E_FORMATO;
464122b6 481
3c87527e
GRG
482 /* check for and animated GIF support (ver. >= 89a) */
483 m_f->SeekI(0, wxFromStart);
464122b6
JS
484 m_f->Read(buf, 6);
485
464122b6
JS
486 if (memcmp(buf + 3, "89a", 3) < 0)
487 m_anim = FALSE;
488
489 /* read logical screen descriptor block (LSDB) */
490 m_f->Read(buf, 7);
491 m_screenw = buf[0] + 256 * buf[1];
492 m_screenh = buf[2] + 256 * buf[3];
493
494 /* load global color map if available */
495 if ((buf[4] & 0x80) == 0x80)
496 {
497 m_background = buf[5];
498
499 ncolors = 2 << (buf[4] & 0x07);
500 m_f->Read(pal, 3 * ncolors);
501 }
502
503 /* transparent colour, disposal method and delay default to unused */
504 transparent = -1;
505 disposal = -1;
506 delay = -1;
507
508 /* read images */
509 ppimg = &m_pfirst;
510 pprev = NULL;
511 pimg = NULL;
512
513 while (1)
514 {
515 type = (unsigned char)m_f->GetC();
516
517 /* end of data? */
518 if (type == 0x3B)
519 break;
520
521 /* extension block? */
522 if (type == 0x21)
523 {
524 if (((unsigned char)m_f->GetC()) == 0xF9)
525 /* graphics control extension, parse it */
526 {
527 m_f->Read(buf, 6);
528
529 /* read delay and convert from 1/100 of a second to ms */
530 delay = 10 * (buf[2] + 256 * buf[3]);
531
532 /* read transparent colour index, if used */
533 if (buf[1] & 0x01)
534 transparent = buf[4];
535
536 /* read disposal method */
537 disposal = (buf[1] & 0x1C) - 1;
538 }
539 else
540 /* other extension, skip */
541 {
542 while ((i = (unsigned char)m_f->GetC()) != 0)
543 {
544 /* This line should not be neccessary!
545 * Some images are not loaded correctly
546 * without it. A bug in wxStream?
5b4f8dd5 547 * Yes. Fixed now.
464122b6
JS
548 */
549 // m_f->SeekI(m_f->TellI(), wxFromStart);
5b4f8dd5 550
464122b6
JS
551 m_f->SeekI(i, wxFromCurrent);
552 }
553 }
554 }
555
556 /* image descriptor block? */
557 if (type == 0x2C)
558 {
559 /* allocate memory for IMAGEN struct */
560 pimg = (*ppimg) = (IMAGEN *) malloc(sizeof(IMAGEN));
561
562 if (pimg == NULL)
563 {
564 Destroy();
565 return E_MEMORIA;
566 }
567
568 /* fill in the data */
569 m_f->Read(buf, 9);
570 pimg->left = buf[4] + 256 * buf[5];
571 pimg->top = buf[4] + 256 * buf[5];
572 pimg->w = buf[4] + 256 * buf[5];
573 pimg->h = buf[6] + 256 * buf[7];
574 interl = ((buf[8] & 0x40)? 1 : 0);
575 size = pimg->w * pimg->h;
576
577 pimg->transparent = transparent;
578 pimg->disposal = disposal;
579 pimg->delay = delay;
580 pimg->next = NULL;
581 pimg->prev = pprev;
582 pprev = pimg;
583 ppimg = &pimg->next;
584
585 /* allocate memory for image and palette */
586 pimg->p = (unsigned char *) malloc(size);
587 pimg->pal = (unsigned char *) malloc(768);
588
589 if ((!pimg->p) || (!pimg->pal))
590 {
591 Destroy();
592 return E_MEMORIA;
593 }
594
595 /* load local color map if available, else use global map */
596 if ((buf[8] & 0x80) == 0x80)
597 {
598 ncolors = 2 << (buf[8] & 0x07);
599 m_f->Read(pimg->pal, 3 * ncolors);
600 }
601 else
602 memcpy(pimg->pal, pal, 768);
603
604 /* get initial code size from first byte in raster data */
605 bits = (unsigned char)m_f->GetC();
606
607 /* decode image */
608 dgif(pimg, interl, bits);
609
610 m_nimages++;
611 }
612
613 /* if we have one image and no animated GIF support, exit */
614 if (m_nimages == 1 && !m_anim)
615 break;
616 }
617
618 /* finish successfully :-) */
619 if (m_nimages != 0)
620 {
621 m_image = 1;
622 m_plast = pimg;
623 m_pimage = m_pfirst;
624 }
625
626 return E_OK;
627}
628
629#endif // wxUSE_STREAM