]>
git.saurik.com Git - wxWidgets.git/blob - src/common/iffdecod.cpp
d36a9c5d0e7b6b5f2456c9f1e3586c097f762348
2 // iffdecod.cc - image handler for IFF/ILBM images
3 // parts of the source are based on xviff by Thomas Meyer
4 // Permission for use in wxWindows has been gratefully given.
6 // (c) Steffen Gutmann, 2002
8 // Creation date: 08.01.2002
9 // Last modified: 12.01.2002
13 #pragma implementation "iffdecod.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
30 #include "wx/iffdecod.h"
32 #if wxUSE_STREAMS && wxUSE_IFF
34 //---------------------------------------------------------------------------
35 // wxIFFDecoder constructor and destructor
36 //---------------------------------------------------------------------------
38 wxIFFDecoder::wxIFFDecoder(wxInputStream
*s
)
46 void wxIFFDecoder::Destroy()
56 //---------------------------------------------------------------------------
57 // Convert this image to a wxImage object
58 //---------------------------------------------------------------------------
60 // This function was designed by Vaclav Slavik
62 bool wxIFFDecoder::ConvertToImage(wxImage
*image
) const
68 image
->Create(GetWidth(), GetHeight());
73 unsigned char *pal
= GetPalette();
74 unsigned char *src
= GetData();
75 unsigned char *dst
= image
->GetData();
76 int colors
= GetNumColors();
77 int transparent
= GetTransparentColour();
80 // set transparent colour mask
81 if (transparent
!= -1)
83 for (i
= 0; i
< colors
; i
++)
85 if ((pal
[3 * i
+ 0] == 255) &&
86 (pal
[3 * i
+ 1] == 0) &&
87 (pal
[3 * i
+ 2] == 255))
93 pal
[3 * transparent
+ 0] = 255,
94 pal
[3 * transparent
+ 1] = 0,
95 pal
[3 * transparent
+ 2] = 255;
97 image
->SetMaskColour(255, 0, 255);
100 image
->SetMask(FALSE
);
103 if (pal
&& colors
> 0)
105 unsigned char r
[colors
];
106 unsigned char g
[colors
];
107 unsigned char b
[colors
];
109 for (i
= 0; i
< colors
; i
++)
116 image
->SetPalette(wxPalette(colors
, r
, g
, b
));
118 #endif // wxUSE_PALETTE
121 for (i
= 0; i
< (long)(GetWidth() * GetHeight()); i
++, src
+= 3, dst
+= 3)
132 //---------------------------------------------------------------------------
134 //---------------------------------------------------------------------------
136 // Get data for current frame
138 unsigned char* wxIFFDecoder::GetData() const { return (m_image
->p
); }
139 unsigned char* wxIFFDecoder::GetPalette() const { return (m_image
->pal
); }
140 int wxIFFDecoder::GetNumColors() const { return m_image
->colors
; }
141 unsigned int wxIFFDecoder::GetWidth() const { return (m_image
->w
); }
142 unsigned int wxIFFDecoder::GetHeight() const { return (m_image
->h
); }
143 int wxIFFDecoder::GetTransparentColour() const { return m_image
->transparent
; }
145 //---------------------------------------------------------------------------
146 // IFF reading and decoding
147 //---------------------------------------------------------------------------
151 // Returns TRUE if the file looks like a valid IFF, FALSE otherwise.
153 bool wxIFFDecoder::CanRead()
155 unsigned char buf
[12] = "";
158 m_f
->SeekI(-12, wxFromCurrent
);
160 return (memcmp(buf
, "FORM", 4) == 0 && memcmp(buf
+8, "ILBM", 4) == 0);
165 // Based on xv source code by Thomas Meyer
166 // Permission for use in wxWindows has been gratefully given.
168 typedef unsigned char byte
;
171 /*************************************************************************
172 void decomprle(source, destination, source length, buffer size)
174 Decompress run-length encoded data from source to destination. Terminates
175 when source is decoded completely or destination buffer is full.
177 The decruncher is as optimized as I could make it, without risking
178 safety in case of corrupt BODY chunks.
179 **************************************************************************/
181 static void decomprle(const byte
*sptr
, byte
*dptr
, long slen
, long dlen
)
183 byte codeByte
, dataByte
;
185 while ((slen
> 0) && (dlen
> 0)) {
189 if (codeByte
< 0x80) {
191 if ((slen
> (long) codeByte
) && (dlen
>= (long) codeByte
)) {
192 slen
-= codeByte
+ 1;
194 while (codeByte
> 0) {
202 else if (codeByte
> 0x80) {
203 codeByte
= 0x81 - (codeByte
& 0x7f);
204 if ((slen
> (long) 0) && (dlen
>= (long) codeByte
)) {
208 while (codeByte
> 0) {
218 /******************************************/
219 static unsigned int iff_getword(const byte
*ptr
)
228 /******************************************/
229 static unsigned long iff_getlong(const byte
*ptr
)
234 l
= (l
<< 8) + *ptr
++;
235 l
= (l
<< 8) + *ptr
++;
240 // Define internal ILBM types
241 #define ILBM_NORMAL 0
247 int wxIFFDecoder::ReadIFF()
251 m_image
= new IFFImage();
257 // compute file length
258 off_t currentPos
= m_f
->TellI();
259 m_f
->SeekI(0, wxFromEnd
);
260 long filesize
= m_f
->TellI();
261 m_f
->SeekI(currentPos
, wxFromStart
);
263 // allocate memory for complete file
264 if ((databuf
= new byte
[filesize
]) == 0) {
269 m_f
->Read(databuf
, filesize
);
270 const byte
*dataend
= databuf
+ filesize
;
272 // initialize work pointer. used to trace the buffer for IFF chunks
273 const byte
*dataptr
= databuf
;
275 // check for minmal size
276 if (dataptr
+ 12 > dataend
) {
278 return wxIFF_INVFORMAT
;
281 // check if we really got an IFF file
282 if (strncmp((char *)dataptr
, "FORM", 4) != 0) {
284 return wxIFF_INVFORMAT
;
287 dataptr
= dataptr
+ 8; // skip ID and length of FORM
289 // check if the IFF file is an ILBM (picture) file
290 if (strncmp((char *) dataptr
, "ILBM", 4) != 0) {
292 return wxIFF_INVFORMAT
;
295 wxLogTrace(_T("iff"), _T("IFF ILBM file recognized"));
297 dataptr
= dataptr
+ 4; // skip ID
300 // main decoding loop. searches IFF chunks and handles them.
301 // terminates when BODY chunk was found or dataptr ran over end of file
303 bool BMHDok
= false, CMAPok
= false, CAMGok
= false;
304 int bmhd_width
= 0, bmhd_height
= 0, bmhd_bitplanes
= 0, bmhd_transcol
= -1;
305 byte bmhd_masking
= 0, bmhd_compression
= 0;
306 long camg_viewmode
= 0;
308 while (dataptr
+ 8 <= dataend
) {
309 // get chunk length and make even
310 size_t chunkLen
= (iff_getlong(dataptr
+ 4) + 1) & 0xfffffffe;
311 if (chunkLen
< 0) { // format error?
314 bool truncated
= (dataptr
+ 8 + chunkLen
> dataend
);
316 if (strncmp((char *)dataptr
, "BMHD", 4) == 0) { // BMHD chunk?
317 if (chunkLen
< 12 + 2 || truncated
) {
320 bmhd_width
= iff_getword(dataptr
+ 8); // width of picture
321 bmhd_height
= iff_getword(dataptr
+ 8 + 2); // height of picture
322 bmhd_bitplanes
= *(dataptr
+ 8 + 8); // # of bitplanes
323 bmhd_masking
= *(dataptr
+ 8 + 9);
324 bmhd_compression
= *(dataptr
+ 8 + 10); // get compression
325 bmhd_transcol
= iff_getword(dataptr
+ 8 + 12);
326 BMHDok
= true; // got BMHD
327 dataptr
+= 8 + chunkLen
; // to next chunk
329 else if (strncmp((char *)dataptr
, "CMAP", 4) == 0) { // CMAP ?
333 const byte
*cmapptr
= dataptr
+ 8;
334 colors
= chunkLen
/ 3; // calc no of colors
338 m_image
->colors
= colors
;
340 m_image
->pal
= new byte
[3*colors
];
346 // copy colors to color map
347 for (int i
=0; i
< colors
; i
++) {
348 m_image
->pal
[3*i
+ 0] = *cmapptr
++;
349 m_image
->pal
[3*i
+ 1] = *cmapptr
++;
350 m_image
->pal
[3*i
+ 2] = *cmapptr
++;
354 wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."),
357 CMAPok
= true; // got CMAP
358 dataptr
+= 8 + chunkLen
; // to next chunk
359 } else if (strncmp((char *)dataptr
, "CAMG", 4) == 0) { // CAMG ?
360 if (chunkLen
< 4 || truncated
) {
363 camg_viewmode
= iff_getlong(dataptr
+ 8); // get viewmodes
364 CAMGok
= true; // got CAMG
365 dataptr
+= 8 + chunkLen
; // to next chunk
367 else if (strncmp((char *)dataptr
, "BODY", 4) == 0) { // BODY ?
368 if (!BMHDok
) { // BMHD found?
371 const byte
*bodyptr
= dataptr
+ 8; // -> BODY data
374 chunkLen
= dataend
- dataptr
;
378 // if BODY is compressed, allocate buffer for decrunched BODY
379 // and decompress it (run length encoding)
381 if (bmhd_compression
== 1) {
382 // calc size of decrunch buffer - (size of the actual pic.
383 // decompressed in interleaved Amiga bitplane format)
385 size_t decomp_bufsize
= (((bmhd_width
+ 15) >> 4) << 1)
386 * bmhd_height
* bmhd_bitplanes
;
388 if ((decomp_mem
= new byte
[decomp_bufsize
]) == 0) {
393 decomprle(bodyptr
, decomp_mem
, chunkLen
, decomp_bufsize
);
394 bodyptr
= decomp_mem
; // -> uncompressed BODY
395 chunkLen
= decomp_bufsize
;
400 // the following determines the type of the ILBM file.
401 // it's either NORMAL, EHB, HAM, HAM8 or 24BIT
403 int fmt
= ILBM_NORMAL
; // assume normal ILBM
404 if (bmhd_bitplanes
== 24) {
406 } else if (bmhd_bitplanes
== 8) {
407 if (CAMGok
&& (camg_viewmode
& 0x800)) {
410 } else if ((bmhd_bitplanes
> 5) && CAMGok
) {
411 if (camg_viewmode
& 0x80) {
413 } else if (camg_viewmode
& 0x800) {
418 wxLogTrace(_T("iff"),
419 _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"),
420 (fmt
==ILBM_NORMAL
) ? "Normal ILBM" :
421 (fmt
==ILBM_HAM
) ? "HAM ILBM" :
422 (fmt
==ILBM_HAM8
) ? "HAM8 ILBM" :
423 (fmt
==ILBM_EHB
) ? "EHB ILBM" :
424 (fmt
==ILBM_24BIT
) ? "24BIT ILBM" : "unknown ILBM",
425 bmhd_width
, bmhd_height
, bmhd_bitplanes
,
426 1<<bmhd_bitplanes
, bmhd_compression
);
428 if ((fmt
==ILBM_NORMAL
) || (fmt
==ILBM_EHB
) || (fmt
==ILBM_HAM
)) {
429 wxLogTrace(_T("iff"),
430 _T("Converting CMAP from normal ILBM CMAP"));
433 case ILBM_NORMAL
: colors
= 1 << bmhd_bitplanes
; break;
434 case ILBM_EHB
: colors
= 32*2; break;
435 case ILBM_HAM
: colors
= 16; break;
438 if (colors
> m_image
->colors
) {
439 byte
*pal
= new byte
[colors
*3];
445 for (i
= 0; i
< m_image
->colors
; i
++) {
446 pal
[3*i
+ 0] = m_image
->pal
[3*i
+ 0];
447 pal
[3*i
+ 1] = m_image
->pal
[3*i
+ 1];
448 pal
[3*i
+ 2] = m_image
->pal
[3*i
+ 2];
450 for (; i
< colors
; i
++) {
457 m_image
->colors
= colors
;
460 for (int i
=0; i
< colors
; i
++) {
461 m_image
->pal
[3*i
+ 0] = (m_image
->pal
[3*i
+ 0] >> 4) * 17;
462 m_image
->pal
[3*i
+ 1] = (m_image
->pal
[3*i
+ 1] >> 4) * 17;
463 m_image
->pal
[3*i
+ 2] = (m_image
->pal
[3*i
+ 2] >> 4) * 17;
467 m_image
->p
= new byte
[bmhd_width
* bmhd_height
* 3];
468 byte
*picptr
= m_image
->p
;
474 byte
*pal
= m_image
->pal
;
475 int lineskip
= ((bmhd_width
+ 15) >> 4) << 1;
476 int height
= chunkLen
/ (lineskip
* bmhd_bitplanes
);
478 if (bmhd_height
< height
) {
479 height
= bmhd_height
;
482 if (fmt
== ILBM_HAM
|| fmt
== ILBM_HAM8
|| fmt
== ILBM_24BIT
) {
484 const byte
*workptr
= bodyptr
;
486 for (int i
=0; i
< height
; i
++) {
488 const byte
*workptr2
= workptr
;
490 // at start of each line, init RGB values to background
495 for (int j
=0; j
< bmhd_width
; j
++) {
498 const byte
*workptr3
= workptr2
;
499 for (int k
=0; k
< bmhd_bitplanes
; k
++) {
500 if (*workptr3
& bitmsk
) {
503 workptr3
+= lineskip
;
508 int c
= (col
& 0x0f);
509 switch (col
& 0x30) {
510 case 0x00: if (c
>= 0 && c
< colors
) {
517 case 0x10: bval
= c
* 17;
520 case 0x20: rval
= c
* 17;
523 case 0x30: gval
= c
* 17;
526 } else if (fmt
== ILBM_HAM8
) {
527 int c
= (col
& 0x3f);
529 case 0x00: if (c
>= 0 & c
< colors
) {
536 case 0x40: bval
= (bval
& 3) | (c
<< 2);
539 case 0x80: rval
= (rval
& 3) | (c
<< 2);
542 case 0xc0: gval
= (rval
& 3) | (c
<< 2);
546 gval
= (col
>> 8) & 0xff;
547 bval
= (col
>> 16) & 0xff;
554 bitmsk
= bitmsk
>> 1;
560 workptr
+= lineskip
* bmhd_bitplanes
;
562 } else if ((fmt
== ILBM_NORMAL
) || (fmt
== ILBM_EHB
)) {
563 if (fmt
== ILBM_EHB
) {
564 wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode"));
566 for (int i
=0; i
<32; i
++) {
567 pal
[3*(i
+ 32) + 0] = pal
[3*i
+ 0] >> 1;
568 pal
[3*(i
+ 32) + 1] = pal
[3*i
+ 1] >> 1;
569 pal
[3*(i
+ 32) + 2] = pal
[3*i
+ 2] >> 1;
573 byte
*pic
= picptr
; // ptr to buffer
574 const byte
*workptr
= bodyptr
; // ptr to pic, planar format
576 if (bmhd_height
< height
) {
577 height
= bmhd_height
;
580 for (int i
=0; i
< height
; i
++) {
581 byte bitmsk
= 0x80; // left most bit (mask)
582 const byte
*workptr2
= workptr
; // work ptr to source
583 for (int j
=0; j
< bmhd_width
; j
++) {
586 const byte
*workptr3
= workptr2
; // 1st byte in 1st pln
588 for (int k
=0; k
< bmhd_bitplanes
; k
++) {
589 if (*workptr3
& bitmsk
) { // if bit set in this pln
590 col
= col
+ colbit
; // add bit to chunky byte
592 workptr3
+= lineskip
; // go to next line
593 colbit
<<= 1; // shift color bit
596 if (col
>= 0 && col
< colors
) {
597 pic
[0] = pal
[3*col
+ 0];
598 pic
[1] = pal
[3*col
+ 1];
599 pic
[2] = pal
[3*col
+ 2];
601 pic
[0] = pic
[1] = pic
[2] = 0;
604 bitmsk
= bitmsk
>> 1; // shift mask to next bit
605 if (bitmsk
== 0) { // if mask is zero
606 bitmsk
= 0x80; // reset mask
607 workptr2
++; // mv ptr to next byte
611 workptr
+= lineskip
* bmhd_bitplanes
; // to next line
614 break; // unknown format
617 m_image
->w
= bmhd_width
;
619 m_image
->transparent
= bmhd_transcol
;
621 wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"),
622 truncated
? "truncated" : "completely");
624 return (truncated
? wxIFF_TRUNCATED
: wxIFF_OK
);
626 wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"),
627 *dataptr
, *(dataptr
+1), *(dataptr
+2), *(dataptr
+3));
629 dataptr
= dataptr
+ 8 + chunkLen
; // skip unknown chunk
634 return wxIFF_INVFORMAT
;
637 #endif // wxUSE_STREAMS && wxUSE_IFF