Remove all lines containing cvs/svn "$Id$" keyword.
[wxWidgets.git] / src / common / imagiff.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/imagiff.cpp
3 // Purpose: wxImage handler for Amiga IFF images
4 // Author: Steffen Gutmann, Thomas Meyer
5 // Copyright: (c) Steffen Gutmann, 2002
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 // Parts of this source are based on the iff loading algorithm found
10 // in xviff.c. Permission by the original author, Thomas Meyer, and
11 // by the author of xv, John Bradley for using the iff loading part
12 // in wxWidgets has been gratefully given.
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #if wxUSE_IMAGE && wxUSE_IFF
22
23 #ifndef WX_PRECOMP
24 #include "wx/log.h"
25 #include "wx/intl.h"
26 #endif
27
28 #include "wx/imagiff.h"
29 #include "wx/wfstream.h"
30
31 #if wxUSE_PALETTE
32 #include "wx/palette.h"
33 #endif // wxUSE_PALETTE
34
35 #include <stdlib.h>
36 #include <string.h>
37
38
39 // --------------------------------------------------------------------------
40 // Constants
41 // --------------------------------------------------------------------------
42
43 // Error codes:
44 // Note that the error code wxIFF_TRUNCATED means that the image itself
45 // is most probably OK, but the decoder didn't reach the end of the data
46 // stream; this means that if it was not reading directly from file,
47 // the stream will not be correctly positioned.
48 //
49
50 enum
51 {
52 wxIFF_OK = 0, /* everything was OK */
53 wxIFF_INVFORMAT, /* error in iff header */
54 wxIFF_MEMERR, /* error allocating memory */
55 wxIFF_TRUNCATED /* file appears to be truncated */
56 };
57
58 // --------------------------------------------------------------------------
59 // wxIFFDecoder class
60 // --------------------------------------------------------------------------
61
62 // internal class for storing IFF image data
63 class IFFImage
64 {
65 public:
66 unsigned int w; /* width */
67 unsigned int h; /* height */
68 int transparent; /* transparent color (-1 = none) */
69 int colors; /* number of colors */
70 unsigned char *p; /* bitmap */
71 unsigned char *pal; /* palette */
72
73 IFFImage() : w(0), h(0), colors(0), p(0), pal(0) {}
74 ~IFFImage() { delete [] p; delete [] pal; }
75 };
76
77 class WXDLLEXPORT wxIFFDecoder
78 {
79 private:
80 IFFImage *m_image; // image data
81 wxInputStream *m_f; // input stream
82 unsigned char *databuf;
83 unsigned char *decomp_mem;
84
85 void Destroy();
86
87 public:
88 // get data of current frame
89 unsigned char* GetData() const;
90 unsigned char* GetPalette() const;
91 int GetNumColors() const;
92 unsigned int GetWidth() const;
93 unsigned int GetHeight() const;
94 int GetTransparentColour() const;
95
96 // constructor, destructor, etc.
97 wxIFFDecoder(wxInputStream *s);
98 ~wxIFFDecoder() { Destroy(); }
99
100 // NOTE: this function modifies the current stream position
101 bool CanRead();
102
103 int ReadIFF();
104 bool ConvertToImage(wxImage *image) const;
105 };
106
107
108 //---------------------------------------------------------------------------
109 // wxIFFDecoder constructor and destructor
110 //---------------------------------------------------------------------------
111
112 wxIFFDecoder::wxIFFDecoder(wxInputStream *s)
113 {
114 m_f = s;
115 m_image = 0;
116 databuf = 0;
117 decomp_mem = 0;
118 }
119
120 void wxIFFDecoder::Destroy()
121 {
122 wxDELETE(m_image);
123 wxDELETEA(databuf);
124 wxDELETEA(decomp_mem);
125 }
126
127 //---------------------------------------------------------------------------
128 // Convert this image to a wxImage object
129 //---------------------------------------------------------------------------
130
131 // This function was designed by Vaclav Slavik
132
133 bool wxIFFDecoder::ConvertToImage(wxImage *image) const
134 {
135 // just in case...
136 image->Destroy();
137
138 // create the image
139 image->Create(GetWidth(), GetHeight());
140
141 if (!image->IsOk())
142 return false;
143
144 unsigned char *pal = GetPalette();
145 unsigned char *src = GetData();
146 unsigned char *dst = image->GetData();
147 int colors = GetNumColors();
148 int transparent = GetTransparentColour();
149 long i;
150
151 // set transparent colour mask
152 if (transparent != -1)
153 {
154 for (i = 0; i < colors; i++)
155 {
156 if ((pal[3 * i + 0] == 255) &&
157 (pal[3 * i + 1] == 0) &&
158 (pal[3 * i + 2] == 255))
159 {
160 pal[3 * i + 2] = 254;
161 }
162 }
163
164 pal[3 * transparent + 0] = 255,
165 pal[3 * transparent + 1] = 0,
166 pal[3 * transparent + 2] = 255;
167
168 image->SetMaskColour(255, 0, 255);
169 }
170 else
171 image->SetMask(false);
172
173 #if wxUSE_PALETTE
174 if (pal && colors > 0)
175 {
176 unsigned char* r = new unsigned char[colors];
177 unsigned char* g = new unsigned char[colors];
178 unsigned char* b = new unsigned char[colors];
179
180 for (i = 0; i < colors; i++)
181 {
182 r[i] = pal[3*i + 0];
183 g[i] = pal[3*i + 1];
184 b[i] = pal[3*i + 2];
185 }
186
187 image->SetPalette(wxPalette(colors, r, g, b));
188
189 delete [] r;
190 delete [] g;
191 delete [] b;
192 }
193 #endif // wxUSE_PALETTE
194
195 // copy image data
196 for (i = 0; i < (long)(GetWidth() * GetHeight()); i++, src += 3, dst += 3)
197 {
198 dst[0] = src[0];
199 dst[1] = src[1];
200 dst[2] = src[2];
201 }
202
203 return true;
204 }
205
206
207 //---------------------------------------------------------------------------
208 // Data accessors
209 //---------------------------------------------------------------------------
210
211 // Get data for current frame
212
213 unsigned char* wxIFFDecoder::GetData() const { return (m_image->p); }
214 unsigned char* wxIFFDecoder::GetPalette() const { return (m_image->pal); }
215 int wxIFFDecoder::GetNumColors() const { return m_image->colors; }
216 unsigned int wxIFFDecoder::GetWidth() const { return (m_image->w); }
217 unsigned int wxIFFDecoder::GetHeight() const { return (m_image->h); }
218 int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; }
219
220 //---------------------------------------------------------------------------
221 // IFF reading and decoding
222 //---------------------------------------------------------------------------
223
224 //
225 // CanRead:
226 // Returns true if the file looks like a valid IFF, false otherwise.
227 //
228 bool wxIFFDecoder::CanRead()
229 {
230 unsigned char buf[12];
231
232 if ( !m_f->Read(buf, WXSIZEOF(buf)) )
233 return false;
234
235 return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0);
236 }
237
238
239 // ReadIFF:
240 // Based on xv source code by Thomas Meyer
241 // Permission for use in wxWidgets has been gratefully given.
242
243 typedef unsigned char byte;
244 #define IFFDEBUG 0
245
246 /*************************************************************************
247 void decomprle(source, destination, source length, buffer size)
248
249 Decompress run-length encoded data from source to destination. Terminates
250 when source is decoded completely or destination buffer is full.
251
252 The decruncher is as optimized as I could make it, without risking
253 safety in case of corrupt BODY chunks.
254 **************************************************************************/
255
256 static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen)
257 {
258 byte codeByte, dataByte;
259
260 while ((slen > 0) && (dlen > 0)) {
261 // read control byte
262 codeByte = *sptr++;
263
264 if (codeByte < 0x80) {
265 codeByte++;
266 if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) {
267 slen -= codeByte + 1;
268 dlen -= codeByte;
269 while (codeByte > 0) {
270 *dptr++ = *sptr++;
271 codeByte--;
272 }
273 }
274 else slen = 0;
275 }
276
277 else if (codeByte > 0x80) {
278 codeByte = 0x81 - (codeByte & 0x7f);
279 if ((slen > (long) 0) && (dlen >= (long) codeByte)) {
280 dataByte = *sptr++;
281 slen -= 2;
282 dlen -= codeByte;
283 while (codeByte > 0) {
284 *dptr++ = dataByte;
285 codeByte--;
286 }
287 }
288 else slen = 0;
289 }
290 }
291 }
292
293 /******************************************/
294 static unsigned int iff_getword(const byte *ptr)
295 {
296 unsigned int v;
297
298 v = *ptr++;
299 v = (v << 8) + *ptr;
300 return v;
301 }
302
303 /******************************************/
304 static unsigned long iff_getlong(const byte *ptr)
305 {
306 unsigned long l;
307
308 l = *ptr++;
309 l = (l << 8) + *ptr++;
310 l = (l << 8) + *ptr++;
311 l = (l << 8) + *ptr;
312 return l;
313 }
314
315 // Define internal ILBM types
316 #define ILBM_NORMAL 0
317 #define ILBM_EHB 1
318 #define ILBM_HAM 2
319 #define ILBM_HAM8 3
320 #define ILBM_24BIT 4
321
322 int wxIFFDecoder::ReadIFF()
323 {
324 Destroy();
325
326 m_image = new IFFImage();
327 if (m_image == 0) {
328 Destroy();
329 return wxIFF_MEMERR;
330 }
331
332 // compute file length
333 wxFileOffset currentPos = m_f->TellI();
334 if (m_f->SeekI(0, wxFromEnd) == wxInvalidOffset) {
335 Destroy();
336 return wxIFF_MEMERR;
337 }
338
339 long filesize = m_f->TellI();
340 if (m_f->SeekI(currentPos, wxFromStart) == wxInvalidOffset) {
341 Destroy();
342 return wxIFF_MEMERR;
343 }
344
345 // allocate memory for complete file
346 if ((databuf = new byte[filesize]) == 0) {
347 Destroy();
348 return wxIFF_MEMERR;
349 }
350
351 m_f->Read(databuf, filesize);
352 const byte *dataend = databuf + filesize;
353
354 // initialize work pointer. used to trace the buffer for IFF chunks
355 const byte *dataptr = databuf;
356
357 // check for minmal size
358 if (dataptr + 12 > dataend) {
359 Destroy();
360 return wxIFF_INVFORMAT;
361 }
362
363 // check if we really got an IFF file
364 if (strncmp((char *)dataptr, "FORM", 4) != 0) {
365 Destroy();
366 return wxIFF_INVFORMAT;
367 }
368
369 dataptr = dataptr + 8; // skip ID and length of FORM
370
371 // check if the IFF file is an ILBM (picture) file
372 if (strncmp((char *) dataptr, "ILBM", 4) != 0) {
373 Destroy();
374 return wxIFF_INVFORMAT;
375 }
376
377 wxLogTrace(wxT("iff"), wxT("IFF ILBM file recognized"));
378
379 dataptr = dataptr + 4; // skip ID
380
381 //
382 // main decoding loop. searches IFF chunks and handles them.
383 // terminates when BODY chunk was found or dataptr ran over end of file
384 //
385 bool BMHDok = false, CAMGok = false;
386 int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1;
387 byte bmhd_compression = 0;
388 long camg_viewmode = 0;
389 int colors = 0;
390 while (dataptr + 8 <= dataend) {
391 // get chunk length and make even
392 long chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe;
393 if (chunkLen < 0) { // format error?
394 break;
395 }
396 bool truncated = (dataptr + 8 + chunkLen > dataend);
397
398 if (strncmp((char *)dataptr, "BMHD", 4) == 0) { // BMHD chunk?
399 if (chunkLen < 12 + 2 || truncated) {
400 break;
401 }
402 bmhd_width = iff_getword(dataptr + 8); // width of picture
403 bmhd_height= iff_getword(dataptr + 8 + 2); // height of picture
404 bmhd_bitplanes = *(dataptr + 8 + 8); // # of bitplanes
405 // bmhd_masking = *(dataptr + 8 + 9); -- unused currently
406 bmhd_compression = *(dataptr + 8 + 10); // get compression
407 bmhd_transcol = iff_getword(dataptr + 8 + 12);
408 BMHDok = true; // got BMHD
409 dataptr += 8 + chunkLen; // to next chunk
410 }
411 else if (strncmp((char *)dataptr, "CMAP", 4) == 0) { // CMAP ?
412 if (truncated) {
413 break;
414 }
415 const byte *cmapptr = dataptr + 8;
416 colors = chunkLen / 3; // calc no of colors
417
418 wxDELETE(m_image->pal);
419 m_image->colors = colors;
420 if (colors > 0) {
421 m_image->pal = new byte[3*colors];
422 if (!m_image->pal) {
423 Destroy();
424 return wxIFF_MEMERR;
425 }
426
427 // copy colors to color map
428 for (int i=0; i < colors; i++) {
429 m_image->pal[3*i + 0] = *cmapptr++;
430 m_image->pal[3*i + 1] = *cmapptr++;
431 m_image->pal[3*i + 2] = *cmapptr++;
432 }
433 }
434
435 wxLogTrace(wxT("iff"), wxT("Read %d colors from IFF file."),
436 colors);
437
438 dataptr += 8 + chunkLen; // to next chunk
439 } else if (strncmp((char *)dataptr, "CAMG", 4) == 0) { // CAMG ?
440 if (chunkLen < 4 || truncated) {
441 break;
442 }
443 camg_viewmode = iff_getlong(dataptr + 8); // get viewmodes
444 CAMGok = true; // got CAMG
445 dataptr += 8 + chunkLen; // to next chunk
446 }
447 else if (strncmp((char *)dataptr, "BODY", 4) == 0) { // BODY ?
448 if (!BMHDok) { // BMHD found?
449 break;
450 }
451 const byte *bodyptr = dataptr + 8; // -> BODY data
452
453 if (truncated) {
454 chunkLen = dataend - dataptr;
455 }
456
457 //
458 // if BODY is compressed, allocate buffer for decrunched BODY
459 // and decompress it (run length encoding)
460 //
461 if (bmhd_compression == 1) {
462 // calc size of decrunch buffer - (size of the actual pic.
463 // decompressed in interleaved Amiga bitplane format)
464
465 size_t decomp_bufsize = (((bmhd_width + 15) >> 4) << 1)
466 * bmhd_height * bmhd_bitplanes;
467
468 if ((decomp_mem = new byte[decomp_bufsize]) == 0) {
469 Destroy();
470 return wxIFF_MEMERR;
471 }
472
473 decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize);
474 bodyptr = decomp_mem; // -> uncompressed BODY
475 chunkLen = decomp_bufsize;
476 wxDELETEA(databuf);
477 }
478
479 // the following determines the type of the ILBM file.
480 // it's either NORMAL, EHB, HAM, HAM8 or 24BIT
481
482 int fmt = ILBM_NORMAL; // assume normal ILBM
483 if (bmhd_bitplanes == 24) {
484 fmt = ILBM_24BIT;
485 } else if (bmhd_bitplanes == 8) {
486 if (CAMGok && (camg_viewmode & 0x800)) {
487 fmt = ILBM_HAM8;
488 }
489 } else if ((bmhd_bitplanes > 5) && CAMGok) {
490 if (camg_viewmode & 0x80) {
491 fmt = ILBM_EHB;
492 } else if (camg_viewmode & 0x800) {
493 fmt = ILBM_HAM;
494 }
495 }
496
497 wxLogTrace(wxT("iff"),
498 wxT("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"),
499 (fmt==ILBM_NORMAL) ? "Normal ILBM" :
500 (fmt==ILBM_HAM) ? "HAM ILBM" :
501 (fmt==ILBM_HAM8) ? "HAM8 ILBM" :
502 (fmt==ILBM_EHB) ? "EHB ILBM" :
503 (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM",
504 bmhd_width, bmhd_height, bmhd_bitplanes,
505 1<<bmhd_bitplanes, bmhd_compression);
506
507 if ((fmt==ILBM_NORMAL) || (fmt==ILBM_EHB) || (fmt==ILBM_HAM)) {
508 wxLogTrace(wxT("iff"),
509 wxT("Converting CMAP from normal ILBM CMAP"));
510
511 switch(fmt) {
512 case ILBM_NORMAL: colors = 1 << bmhd_bitplanes; break;
513 case ILBM_EHB: colors = 32*2; break;
514 case ILBM_HAM: colors = 16; break;
515 }
516
517 if (colors > m_image->colors) {
518 byte *pal = new byte[colors*3];
519 if (!pal) {
520 Destroy();
521 return wxIFF_MEMERR;
522 }
523 int i;
524 for (i = 0; i < m_image->colors; i++) {
525 pal[3*i + 0] = m_image->pal[3*i + 0];
526 pal[3*i + 1] = m_image->pal[3*i + 1];
527 pal[3*i + 2] = m_image->pal[3*i + 2];
528 }
529 for (; i < colors; i++) {
530 pal[3*i + 0] = 0;
531 pal[3*i + 1] = 0;
532 pal[3*i + 2] = 0;
533 }
534 delete m_image->pal;
535 m_image->pal = pal;
536 m_image->colors = colors;
537 }
538
539 for (int i=0; i < colors; i++) {
540 m_image->pal[3*i + 0] = (m_image->pal[3*i + 0] >> 4) * 17;
541 m_image->pal[3*i + 1] = (m_image->pal[3*i + 1] >> 4) * 17;
542 m_image->pal[3*i + 2] = (m_image->pal[3*i + 2] >> 4) * 17;
543 }
544 }
545
546 m_image->p = new byte[bmhd_width * bmhd_height * 3];
547 byte *picptr = m_image->p;
548 if (!picptr) {
549 Destroy();
550 return wxIFF_MEMERR;
551 }
552
553 byte *pal = m_image->pal;
554 int lineskip = ((bmhd_width + 15) >> 4) << 1;
555 int height = chunkLen / (lineskip * bmhd_bitplanes);
556
557 if (bmhd_height < height) {
558 height = bmhd_height;
559 }
560
561 if (fmt == ILBM_HAM || fmt == ILBM_HAM8 || fmt == ILBM_24BIT) {
562 byte *pic = picptr;
563 const byte *workptr = bodyptr;
564
565 for (int i=0; i < height; i++) {
566 byte bitmsk = 0x80;
567 const byte *workptr2 = workptr;
568
569 // at start of each line, init RGB values to background
570 byte rval = pal[0];
571 byte gval = pal[1];
572 byte bval = pal[2];
573
574 for (int j=0; j < bmhd_width; j++) {
575 long col = 0;
576 long colbit = 1;
577 const byte *workptr3 = workptr2;
578 for (int k=0; k < bmhd_bitplanes; k++) {
579 if (*workptr3 & bitmsk) {
580 col += colbit;
581 }
582 workptr3 += lineskip;
583 colbit <<= 1;
584 }
585
586 if (fmt==ILBM_HAM) {
587 int c = (col & 0x0f);
588 switch (col & 0x30) {
589 case 0x00: if (c >= 0 && c < colors) {
590 rval = pal[3*c + 0];
591 gval = pal[3*c + 1];
592 bval = pal[3*c + 2];
593 }
594 break;
595
596 case 0x10: bval = c * 17;
597 break;
598
599 case 0x20: rval = c * 17;
600 break;
601
602 case 0x30: gval = c * 17;
603 break;
604 }
605 } else if (fmt == ILBM_HAM8) {
606 int c = (col & 0x3f);
607 switch(col & 0xc0) {
608 case 0x00: if (c >= 0 && c < colors) {
609 rval = pal[3*c + 0];
610 gval = pal[3*c + 1];
611 bval = pal[3*c + 2];
612 }
613 break;
614
615 case 0x40: bval = (bval & 3) | (c << 2);
616 break;
617
618 case 0x80: rval = (rval & 3) | (c << 2);
619 break;
620
621 case 0xc0: gval = (rval & 3) | (c << 2);
622 }
623 } else {
624 rval = col & 0xff;
625 gval = (col >> 8) & 0xff;
626 bval = (col >> 16) & 0xff;
627 }
628
629 *pic++ = rval;
630 *pic++ = gval;
631 *pic++ = bval;
632
633 bitmsk = bitmsk >> 1;
634 if (bitmsk == 0) {
635 bitmsk = 0x80;
636 workptr2++;
637 }
638 }
639 workptr += lineskip * bmhd_bitplanes;
640 }
641 } else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) {
642 if (fmt == ILBM_EHB) {
643 wxLogTrace(wxT("iff"), wxT("Doubling CMAP for EHB mode"));
644
645 for (int i=0; i<32; i++) {
646 pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1;
647 pal[3*(i + 32) + 1] = pal[3*i + 1] >> 1;
648 pal[3*(i + 32) + 2] = pal[3*i + 2] >> 1;
649 }
650 }
651
652 byte *pic = picptr; // ptr to buffer
653 const byte *workptr = bodyptr; // ptr to pic, planar format
654
655 if (bmhd_height < height) {
656 height = bmhd_height;
657 }
658
659 for (int i=0; i < height; i++) {
660 byte bitmsk = 0x80; // left most bit (mask)
661 const byte *workptr2 = workptr; // work ptr to source
662 for (int j=0; j < bmhd_width; j++) {
663 long col = 0;
664 long colbit = 1;
665 const byte *workptr3 = workptr2; // 1st byte in 1st pln
666
667 for (int k=0; k < bmhd_bitplanes; k++) {
668 if (*workptr3 & bitmsk) { // if bit set in this pln
669 col = col + colbit; // add bit to chunky byte
670 }
671 workptr3 += lineskip; // go to next line
672 colbit <<= 1; // shift color bit
673 }
674
675 if (col >= 0 && col < colors) {
676 pic[0] = pal[3*col + 0];
677 pic[1] = pal[3*col + 1];
678 pic[2] = pal[3*col + 2];
679 } else {
680 pic[0] = pic[1] = pic[2] = 0;
681 }
682 pic += 3;
683 bitmsk = bitmsk >> 1; // shift mask to next bit
684 if (bitmsk == 0) { // if mask is zero
685 bitmsk = 0x80; // reset mask
686 workptr2++; // mv ptr to next byte
687 }
688 }
689
690 workptr += lineskip * bmhd_bitplanes; // to next line
691 }
692 } else {
693 break; // unknown format
694 }
695
696 m_image->w = bmhd_width;
697 m_image->h = height;
698 m_image->transparent = bmhd_transcol;
699
700 wxLogTrace(wxT("iff"), wxT("Loaded IFF picture %s"),
701 truncated? "truncated" : "completely");
702
703 return (truncated? wxIFF_TRUNCATED : wxIFF_OK);
704 } else {
705 wxLogTrace(wxT("iff"), wxT("Skipping unknown chunk '%c%c%c%c'"),
706 *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3));
707
708 dataptr = dataptr + 8 + chunkLen; // skip unknown chunk
709 }
710 }
711
712 Destroy();
713 return wxIFF_INVFORMAT;
714 }
715
716
717
718 //-----------------------------------------------------------------------------
719 // wxIFFHandler
720 //-----------------------------------------------------------------------------
721
722 IMPLEMENT_DYNAMIC_CLASS(wxIFFHandler, wxImageHandler)
723
724 #if wxUSE_STREAMS
725
726 bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream,
727 bool verbose, int WXUNUSED(index))
728 {
729 wxIFFDecoder *decod;
730 int error;
731 bool ok;
732
733 decod = new wxIFFDecoder(&stream);
734 error = decod->ReadIFF();
735
736 if ((error != wxIFF_OK) && (error != wxIFF_TRUNCATED))
737 {
738 if (verbose)
739 {
740 switch (error)
741 {
742 case wxIFF_INVFORMAT:
743 wxLogError(_("IFF: error in IFF image format."));
744 break;
745 case wxIFF_MEMERR:
746 wxLogError(_("IFF: not enough memory."));
747 break;
748 default:
749 wxLogError(_("IFF: unknown error!!!"));
750 break;
751 }
752 }
753 delete decod;
754 return false;
755 }
756
757 if ((error == wxIFF_TRUNCATED) && verbose)
758 {
759 wxLogError(_("IFF: data stream seems to be truncated."));
760 /* go on; image data is OK */
761 }
762
763 ok = decod->ConvertToImage(image);
764 delete decod;
765
766 return ok;
767 }
768
769 bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image),
770 wxOutputStream& WXUNUSED(stream), bool verbose)
771 {
772 if (verbose)
773 {
774 wxLogDebug(wxT("IFF: the handler is read-only!!"));
775 }
776
777 return false;
778 }
779
780 bool wxIFFHandler::DoCanRead(wxInputStream& stream)
781 {
782 wxIFFDecoder decod(&stream);
783
784 return decod.CanRead();
785 // it's ok to modify the stream position here
786 }
787
788 #endif // wxUSE_STREAMS
789
790 #endif // wxUSE_IFF