]>
git.saurik.com Git - wxWidgets.git/blob - src/common/iffdecod.cpp
423f182d10583732c942de73884952bae3ca3a2a
   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 
= new unsigned char[colors
]; 
 106         unsigned char* g 
= new unsigned char[colors
]; 
 107         unsigned char* b 
= new unsigned char[colors
]; 
 109         for (i 
= 0; i 
< colors
; i
++) 
 116         image
->SetPalette(wxPalette(colors
, r
, g
, b
)); 
 122 #endif // wxUSE_PALETTE 
 125     for (i 
= 0; i 
< (long)(GetWidth() * GetHeight()); i
++, src 
+= 3, dst 
+= 3) 
 136 //--------------------------------------------------------------------------- 
 138 //--------------------------------------------------------------------------- 
 140 // Get data for current frame 
 142 unsigned char* wxIFFDecoder::GetData() const    { return (m_image
->p
); } 
 143 unsigned char* wxIFFDecoder::GetPalette() const { return (m_image
->pal
); } 
 144 int wxIFFDecoder::GetNumColors() const          { return m_image
->colors
; } 
 145 unsigned int wxIFFDecoder::GetWidth() const     { return (m_image
->w
); } 
 146 unsigned int wxIFFDecoder::GetHeight() const    { return (m_image
->h
); } 
 147 int wxIFFDecoder::GetTransparentColour() const { return m_image
->transparent
; } 
 149 //--------------------------------------------------------------------------- 
 150 // IFF reading and decoding 
 151 //--------------------------------------------------------------------------- 
 155 //  Returns TRUE if the file looks like a valid IFF, FALSE otherwise. 
 157 bool wxIFFDecoder::CanRead() 
 159     unsigned char buf
[12] = ""; 
 162     m_f
->SeekI(-12, wxFromCurrent
); 
 164     return (memcmp(buf
, "FORM", 4) == 0 && memcmp(buf
+8, "ILBM", 4) == 0); 
 169 // Based on xv source code by Thomas Meyer 
 170 // Permission for use in wxWindows has been gratefully given. 
 172 typedef unsigned char byte
; 
 175 /************************************************************************* 
 176   void decomprle(source, destination, source length, buffer size) 
 178   Decompress run-length encoded data from source to destination. Terminates 
 179   when source is decoded completely or destination buffer is full. 
 181   The decruncher is as optimized as I could make it, without risking 
 182   safety in case of corrupt BODY chunks. 
 183 **************************************************************************/ 
 185 static void decomprle(const byte 
*sptr
, byte 
*dptr
, long slen
, long dlen
) 
 187     byte codeByte
, dataByte
; 
 189     while ((slen 
> 0) && (dlen 
> 0)) { 
 193     if (codeByte 
< 0x80) { 
 195         if ((slen 
> (long) codeByte
) && (dlen 
>= (long) codeByte
)) { 
 196         slen 
-= codeByte 
+ 1; 
 198         while (codeByte 
> 0) { 
 206     else if (codeByte 
> 0x80) { 
 207         codeByte 
= 0x81 - (codeByte 
& 0x7f); 
 208         if ((slen 
> (long) 0) && (dlen 
>= (long) codeByte
)) { 
 212         while (codeByte 
> 0) { 
 222 /******************************************/ 
 223 static unsigned int iff_getword(const byte 
*ptr
) 
 232 /******************************************/ 
 233 static unsigned long iff_getlong(const byte 
*ptr
) 
 238     l 
= (l 
<< 8) + *ptr
++; 
 239     l 
= (l 
<< 8) + *ptr
++; 
 244 // Define internal ILBM types 
 245 #define ILBM_NORMAL     0 
 251 int wxIFFDecoder::ReadIFF() 
 255     m_image 
= new IFFImage(); 
 261     // compute file length 
 262     off_t currentPos 
= m_f
->TellI(); 
 263     m_f
->SeekI(0, wxFromEnd
); 
 264     long filesize 
= m_f
->TellI(); 
 265     m_f
->SeekI(currentPos
, wxFromStart
); 
 267     // allocate memory for complete file 
 268     if ((databuf 
= new byte
[filesize
]) == 0) { 
 273     m_f
->Read(databuf
, filesize
); 
 274     const byte 
*dataend 
= databuf 
+ filesize
; 
 276     // initialize work pointer. used to trace the buffer for IFF chunks 
 277     const byte 
*dataptr 
= databuf
; 
 279     // check for minmal size 
 280     if (dataptr 
+ 12 > dataend
) { 
 282     return wxIFF_INVFORMAT
; 
 285     // check if we really got an IFF file 
 286     if (strncmp((char *)dataptr
, "FORM", 4) != 0) { 
 288     return wxIFF_INVFORMAT
; 
 291     dataptr 
= dataptr 
+ 8;                  // skip ID and length of FORM 
 293     // check if the IFF file is an ILBM (picture) file 
 294     if (strncmp((char *) dataptr
, "ILBM", 4) != 0) { 
 296     return wxIFF_INVFORMAT
; 
 299     wxLogTrace(_T("iff"), _T("IFF ILBM file recognized")); 
 301     dataptr 
= dataptr 
+ 4;                                // skip ID 
 304     // main decoding loop. searches IFF chunks and handles them. 
 305     // terminates when BODY chunk was found or dataptr ran over end of file 
 307     bool BMHDok 
= false, CMAPok 
= false, CAMGok 
= false; 
 308     int bmhd_width 
= 0, bmhd_height 
= 0, bmhd_bitplanes 
= 0, bmhd_transcol 
= -1; 
 309     byte bmhd_masking 
= 0, bmhd_compression 
= 0; 
 310     long camg_viewmode 
= 0; 
 312     while (dataptr 
+ 8 <= dataend
) { 
 313     // get chunk length and make even 
 314     size_t chunkLen 
= (iff_getlong(dataptr 
+ 4) + 1) & 0xfffffffe; 
 315     if (chunkLen 
< 0) {     // format error? 
 318     bool truncated 
= (dataptr 
+ 8 + chunkLen 
> dataend
); 
 320     if (strncmp((char *)dataptr
, "BMHD", 4) == 0) { // BMHD chunk? 
 321         if (chunkLen 
< 12 + 2 || truncated
) { 
 324         bmhd_width 
= iff_getword(dataptr 
+ 8);      // width of picture 
 325         bmhd_height
= iff_getword(dataptr 
+ 8 + 2);  // height of picture 
 326         bmhd_bitplanes 
= *(dataptr 
+ 8 + 8);        // # of bitplanes 
 327         bmhd_masking  
= *(dataptr 
+ 8 + 9); 
 328         bmhd_compression 
= *(dataptr 
+ 8 + 10);     // get compression 
 329         bmhd_transcol    
= iff_getword(dataptr 
+ 8 + 12); 
 330         BMHDok 
= true;                              // got BMHD 
 331         dataptr 
+= 8 + chunkLen
;                    // to next chunk 
 333     else if (strncmp((char *)dataptr
, "CMAP", 4) == 0) { // CMAP ? 
 337         const byte 
*cmapptr 
= dataptr 
+ 8; 
 338         colors 
= chunkLen 
/ 3;                  // calc no of colors 
 342         m_image
->colors 
= colors
; 
 344         m_image
->pal 
= new byte
[3*colors
]; 
 350         // copy colors to color map 
 351         for (int i
=0; i 
< colors
; i
++) { 
 352             m_image
->pal
[3*i 
+ 0] = *cmapptr
++; 
 353             m_image
->pal
[3*i 
+ 1] = *cmapptr
++; 
 354             m_image
->pal
[3*i 
+ 2] = *cmapptr
++; 
 358         wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."), 
 361         CMAPok 
= true;                              // got CMAP 
 362         dataptr 
+= 8 + chunkLen
;                    // to next chunk 
 363     } else if (strncmp((char *)dataptr
, "CAMG", 4) == 0) { // CAMG ? 
 364         if (chunkLen 
< 4 || truncated
) { 
 367         camg_viewmode 
= iff_getlong(dataptr 
+ 8);   // get viewmodes 
 368         CAMGok 
= true;                              // got CAMG 
 369         dataptr 
+= 8 + chunkLen
;                    // to next chunk 
 371     else if (strncmp((char *)dataptr
, "BODY", 4) == 0) { // BODY ? 
 372         if (!BMHDok
) {                              // BMHD found? 
 375         const byte 
*bodyptr 
= dataptr 
+ 8;          // -> BODY data 
 378         chunkLen 
= dataend 
- dataptr
; 
 382             // if BODY is compressed, allocate buffer for decrunched BODY 
 383         // and decompress it (run length encoding) 
 385         if (bmhd_compression 
== 1) { 
 386         // calc size of decrunch buffer - (size of the actual pic. 
 387         // decompressed in interleaved Amiga bitplane format) 
 389         size_t decomp_bufsize 
= (((bmhd_width 
+ 15) >> 4) << 1) 
 390             * bmhd_height 
* bmhd_bitplanes
; 
 392         if ((decomp_mem 
= new byte
[decomp_bufsize
]) == 0) { 
 397         decomprle(bodyptr
, decomp_mem
, chunkLen
, decomp_bufsize
); 
 398         bodyptr 
= decomp_mem
;                 // -> uncompressed BODY 
 399         chunkLen 
= decomp_bufsize
; 
 404         // the following determines the type of the ILBM file. 
 405         // it's either NORMAL, EHB, HAM, HAM8 or 24BIT 
 407         int fmt 
= ILBM_NORMAL
;                 // assume normal ILBM 
 408         if (bmhd_bitplanes 
== 24) { 
 410         } else if (bmhd_bitplanes 
== 8) { 
 411         if (CAMGok 
&& (camg_viewmode 
& 0x800)) { 
 414         } else if ((bmhd_bitplanes 
> 5) && CAMGok
) { 
 415         if (camg_viewmode 
& 0x80) { 
 417         } else if (camg_viewmode 
& 0x800) { 
 422         wxLogTrace(_T("iff"), 
 423             _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"), 
 424             (fmt
==ILBM_NORMAL
) ? "Normal ILBM" : 
 425             (fmt
==ILBM_HAM
)    ? "HAM ILBM" : 
 426             (fmt
==ILBM_HAM8
)   ? "HAM8 ILBM" : 
 427             (fmt
==ILBM_EHB
)    ? "EHB ILBM" : 
 428             (fmt
==ILBM_24BIT
)  ? "24BIT ILBM" : "unknown ILBM", 
 429             bmhd_width
, bmhd_height
, bmhd_bitplanes
, 
 430             1<<bmhd_bitplanes
, bmhd_compression
); 
 432         if ((fmt
==ILBM_NORMAL
) || (fmt
==ILBM_EHB
) || (fmt
==ILBM_HAM
)) { 
 433         wxLogTrace(_T("iff"), 
 434             _T("Converting CMAP from normal ILBM CMAP")); 
 437             case ILBM_NORMAL
: colors 
= 1 << bmhd_bitplanes
; break; 
 438             case ILBM_EHB
:    colors 
= 32*2; break; 
 439             case ILBM_HAM
:    colors 
= 16; break; 
 442         if (colors 
> m_image
->colors
) { 
 443             byte 
*pal 
= new byte
[colors
*3]; 
 449             for (i 
= 0; i 
< m_image
->colors
; i
++) { 
 450             pal
[3*i 
+ 0] = m_image
->pal
[3*i 
+ 0]; 
 451             pal
[3*i 
+ 1] = m_image
->pal
[3*i 
+ 1]; 
 452             pal
[3*i 
+ 2] = m_image
->pal
[3*i 
+ 2]; 
 454             for (; i 
< colors
; i
++) { 
 461             m_image
->colors 
= colors
; 
 464             for (int i
=0; i 
< colors
; i
++) { 
 465             m_image
->pal
[3*i 
+ 0] = (m_image
->pal
[3*i 
+ 0] >> 4) * 17; 
 466             m_image
->pal
[3*i 
+ 1] = (m_image
->pal
[3*i 
+ 1] >> 4) * 17; 
 467             m_image
->pal
[3*i 
+ 2] = (m_image
->pal
[3*i 
+ 2] >> 4) * 17; 
 471         m_image
->p 
= new byte
[bmhd_width 
* bmhd_height 
* 3]; 
 472             byte 
*picptr 
= m_image
->p
; 
 478         byte 
*pal 
= m_image
->pal
; 
 479         int lineskip 
= ((bmhd_width 
+ 15) >> 4) << 1; 
 480             int height 
= chunkLen 
/ (lineskip 
* bmhd_bitplanes
); 
 482         if (bmhd_height 
< height
) { 
 483             height 
= bmhd_height
; 
 486         if (fmt 
== ILBM_HAM 
|| fmt 
== ILBM_HAM8 
|| fmt 
== ILBM_24BIT
) { 
 488         const byte 
*workptr 
= bodyptr
; 
 490         for (int i
=0; i 
< height
; i
++) { 
 492             const byte 
*workptr2 
= workptr
; 
 494             // at start of each line, init RGB values to background 
 499             for (int j
=0; j 
< bmhd_width
; j
++) { 
 502             const byte 
*workptr3 
= workptr2
; 
 503             for (int k
=0; k 
< bmhd_bitplanes
; k
++) { 
 504                 if (*workptr3 
& bitmsk
) { 
 507                 workptr3 
+= lineskip
; 
 512                 int c 
= (col 
& 0x0f); 
 513                 switch (col 
& 0x30) { 
 514                 case 0x00: if (c 
>= 0 && c 
< colors
) { 
 521                 case 0x10: bval 
= c 
* 17; 
 524                 case 0x20: rval 
= c 
* 17; 
 527                 case 0x30: gval 
= c 
* 17; 
 530             } else if (fmt 
== ILBM_HAM8
) { 
 531                 int c 
= (col 
& 0x3f); 
 533                 case 0x00: if (c 
>= 0 && c 
< colors
) { 
 540                 case 0x40: bval 
= (bval 
& 3) | (c 
<< 2); 
 543                 case 0x80: rval 
= (rval 
& 3) | (c 
<< 2); 
 546                 case 0xc0: gval 
= (rval 
& 3) | (c 
<< 2); 
 550                 gval 
= (col 
>> 8) & 0xff; 
 551                 bval 
= (col 
>> 16) & 0xff; 
 558             bitmsk 
= bitmsk 
>> 1; 
 564             workptr 
+= lineskip 
* bmhd_bitplanes
; 
 566         }  else if ((fmt 
== ILBM_NORMAL
) || (fmt 
== ILBM_EHB
)) { 
 567         if (fmt 
== ILBM_EHB
) { 
 568             wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode")); 
 570             for (int i
=0; i
<32; i
++) { 
 571             pal
[3*(i 
+ 32) + 0] = pal
[3*i 
+ 0] >> 1; 
 572             pal
[3*(i 
+ 32) + 1] = pal
[3*i 
+ 1] >> 1; 
 573             pal
[3*(i 
+ 32) + 2] = pal
[3*i 
+ 2] >> 1; 
 577         byte 
*pic 
= picptr
;         // ptr to buffer 
 578         const byte 
*workptr 
= bodyptr
;  // ptr to pic, planar format 
 580         if (bmhd_height 
< height
) { 
 581             height 
= bmhd_height
; 
 584         for (int i
=0; i 
< height
; i
++) { 
 585             byte bitmsk 
= 0x80;                 // left most bit (mask) 
 586             const byte 
*workptr2 
= workptr
;     // work ptr to source 
 587             for (int j
=0; j 
< bmhd_width
; j
++) { 
 590             const byte 
*workptr3 
= workptr2
;  // 1st byte in 1st pln 
 592             for (int k
=0; k 
< bmhd_bitplanes
; k
++) { 
 593                 if (*workptr3 
& bitmsk
) { // if bit set in this pln 
 594                 col 
= col 
+ colbit
; // add bit to chunky byte 
 596                 workptr3 
+= lineskip
;   // go to next line 
 597                 colbit 
<<= 1;           // shift color bit 
 600             if (col 
>= 0 && col 
< colors
) { 
 601                 pic
[0] = pal
[3*col 
+ 0]; 
 602                 pic
[1] = pal
[3*col 
+ 1]; 
 603                 pic
[2] = pal
[3*col 
+ 2]; 
 605                 pic
[0] = pic
[1] = pic
[2] = 0; 
 608             bitmsk 
= bitmsk 
>> 1;   // shift mask to next bit 
 609             if (bitmsk 
== 0) {      // if mask is zero 
 610                 bitmsk 
= 0x80;      // reset mask 
 611                 workptr2
++;         // mv ptr to next byte 
 615             workptr 
+= lineskip 
* bmhd_bitplanes
;  // to next line 
 618         break;      // unknown format 
 621         m_image
->w 
= bmhd_width
; 
 623         m_image
->transparent 
= bmhd_transcol
; 
 625         wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"), 
 626             truncated
? "truncated" : "completely"); 
 628         return (truncated
? wxIFF_TRUNCATED 
: wxIFF_OK
); 
 630         wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"), 
 631                 *dataptr
, *(dataptr
+1), *(dataptr
+2), *(dataptr
+3)); 
 633         dataptr 
= dataptr 
+ 8 + chunkLen
;      // skip unknown chunk 
 638     return wxIFF_INVFORMAT
; 
 641 #endif // wxUSE_STREAMS && wxUSE_IFF