]>
git.saurik.com Git - wxWidgets.git/blob - src/common/imagbmp.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxImage BMP handler 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "imagbmp.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  21 #include "wx/imagbmp.h" 
  22 #include "wx/bitmap.h" 
  26 #include "wx/filefn.h" 
  27 #include "wx/wfstream.h" 
  29 #include "wx/module.h" 
  44 //----------------------------------------------------------------------------- 
  46 //----------------------------------------------------------------------------- 
  48 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler
,wxImageHandler
) 
  54 bool wxBMPHandler::SaveFile(wxImage 
*image
, 
  55                             wxOutputStream
& stream
, 
  58     wxCHECK_MSG( image
, FALSE
, _T("invalid pointer in wxBMPHandler::SaveFile") ); 
  62         if (verbose
) wxLogError(_("BMP: Couldn't save invalid image.")); 
  66     unsigned width 
= image
->GetWidth(); 
  67     unsigned row_width 
= width 
* 3 +  
  68                          (((width 
% 4) == 0) ? 0 : (4 - (width 
* 3) % 4)); 
  69                          // each row must be aligned to dwords   
  73         wxUint16  magic
;          // format magic, always 'BM' 
  74         wxUint32  filesize
;       // total file size, inc. headers 
  75         wxUint32  reserved
;       // for future use 
  76         wxUint32  data_offset
;    // image data offset in the file 
  79         wxUint32  bih_size
;       // 2nd part's size 
  80         wxUint32  width
, height
;  // bitmap's dimensions 
  81         wxUint16  planes
;         // num of planes 
  82         wxUint16  bpp
;            // bits per pixel 
  83         wxUint32  compression
;    // compression method 
  84         wxUint32  size_of_bmp
;    // size of the bitmap 
  85         wxUint32  h_res
, v_res
;   // image resolution in dpi 
  86         wxUint32  num_clrs
;       // number of colors used 
  87         wxUint32  num_signif_clrs
;// number of significant colors 
  89     wxUint32 hdr_size 
= 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/; 
  91     hdr
.magic 
= wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/); 
  92     hdr
.filesize 
= wxUINT32_SWAP_ON_BE( 
  94                    row_width 
* image
->GetHeight() 
  97     hdr
.data_offset 
= wxUINT32_SWAP_ON_BE(hdr_size
); 
  99     hdr
.bih_size 
= wxUINT32_SWAP_ON_BE(hdr_size 
- 14); 
 100     hdr
.width 
= wxUINT32_SWAP_ON_BE(image
->GetWidth()); 
 101     hdr
.height 
= wxUINT32_SWAP_ON_BE(image
->GetHeight()); 
 102     hdr
.planes 
= wxUINT16_SWAP_ON_BE(1); // always 1 plane 
 103     hdr
.bpp 
= wxUINT16_SWAP_ON_BE(24); // always TrueColor 
 104     hdr
.compression 
= 0; // RGB uncompressed 
 105     hdr
.size_of_bmp 
= wxUINT32_SWAP_ON_BE(row_width 
* image
->GetHeight());  
 106     hdr
.h_res 
= hdr
.v_res 
= wxUINT32_SWAP_ON_BE(72); // 72dpi is standard 
 107     hdr
.num_clrs 
= 0; // maximal possible = 2^24 
 108     hdr
.num_signif_clrs 
= 0; // all colors are significant 
 110     if (// VS: looks ugly but compilers tend to do ugly things with structs, 
 111         //     like aligning hdr.filesize's ofset to dword :( 
 112         // VZ: we should add padding then... 
 113         !stream
.Write(&hdr
.magic
, 2) || 
 114         !stream
.Write(&hdr
.filesize
, 4) || 
 115         !stream
.Write(&hdr
.reserved
, 4) || 
 116         !stream
.Write(&hdr
.data_offset
, 4) || 
 117         !stream
.Write(&hdr
.bih_size
, 4) || 
 118         !stream
.Write(&hdr
.width
, 4) || 
 119         !stream
.Write(&hdr
.height
, 4) || 
 120         !stream
.Write(&hdr
.planes
, 2) || 
 121         !stream
.Write(&hdr
.bpp
, 2) || 
 122         !stream
.Write(&hdr
.compression
, 4) || 
 123         !stream
.Write(&hdr
.size_of_bmp
, 4) || 
 124         !stream
.Write(&hdr
.h_res
, 4) || 
 125         !stream
.Write(&hdr
.v_res
, 4) || 
 126         !stream
.Write(&hdr
.num_clrs
, 4) || 
 127         !stream
.Write(&hdr
.num_signif_clrs
, 4) 
 131             wxLogError(_("BMP: Couldn't write the file header.")); 
 135     wxUint8 
*data 
= (wxUint8
*) image
->GetData(); 
 136     wxUint8 
*buffer 
= new wxUint8
[row_width
]; 
 138     memset(buffer
, 0, row_width
); 
 141     for (y 
= image
->GetHeight() -1 ; y 
>= 0; y
--) 
 143         memcpy(buffer
, data 
+ y 
* 3 * width
, 3 * width
); 
 144         for (x 
= 0; x 
< width
; x
++) 
 146             tmpvar 
= buffer
[3 * x 
+ 0]; 
 147             buffer
[3 * x 
+ 0] = buffer
[3 * x 
+ 2]; 
 148             buffer
[3 * x 
+ 2] = tmpvar
; 
 151         if (!stream
.Write(buffer
, row_width
)) 
 154                 wxLogError(_("BMP: Couldn't write data.")); 
 174 #define BI_BITFIELDS 3 
 177 #define poffset (line * width * 3 + column * 3) 
 179 bool wxBMPHandler::LoadFile( wxImage 
*image
, wxInputStream
& stream
, bool verbose
, int WXUNUSED(index
) ) 
 181     int             rshift 
= 0, gshift 
= 0, bshift 
= 0; 
 184     wxInt32         dbuf
[4], aDword
, 
 185                     rmask 
= 0, gmask 
= 0, bmask 
= 0; 
 188         unsigned char r
, g
, b
; 
 191     off_t start_offset 
= stream
.TellI(); 
 192     if (start_offset 
== wxInvalidOffset
) start_offset 
= 0; 
 197      * Read the BMP header 
 200     stream
.Read( &bbuf
, 2 ); 
 201     stream
.Read( dbuf
, 4 * 4 ); 
 204     wxInt32 size 
= wxINT32_SWAP_ON_BE( dbuf
[0] ); 
 206     wxInt32 offset 
= wxINT32_SWAP_ON_BE( dbuf
[2] ); 
 208     stream
.Read(dbuf
, 4 * 2); 
 209     int width 
= (int)wxINT32_SWAP_ON_BE( dbuf
[0] ); 
 210     int height 
= (int)wxINT32_SWAP_ON_BE( dbuf
[1] ); 
 214             wxLogError( _("BMP: Image width > 32767 pixels for file.") ); 
 220             wxLogError( _("BMP: Image height > 32767 pixels for file.") ); 
 224     stream
.Read( &aWord
, 2 ); 
 227     int planes = (int)wxUINT16_SWAP_ON_BE( aWord ); 
 229     stream
.Read( &aWord
, 2 ); 
 230     int bpp 
= (int)wxUINT16_SWAP_ON_BE( aWord 
); 
 231     if (bpp 
!= 1 && bpp 
!= 4 && bpp 
!= 8 && bpp 
!= 16 && bpp 
!= 24 && bpp 
!= 32) 
 234             wxLogError( _("BMP: Unknown bitdepth in file.") ); 
 238     stream
.Read( dbuf
, 4 * 4 ); 
 239     int comp 
= (int)wxINT32_SWAP_ON_BE( dbuf
[0] ); 
 240     if (comp 
!= BI_RGB 
&& comp 
!= BI_RLE4 
&& comp 
!= BI_RLE8 
&& comp 
!= BI_BITFIELDS
) 
 243             wxLogError( _("BMP: Unknown encoding in file.") ); 
 247     stream
.Read( dbuf
, 4 * 2 ); 
 248     int ncolors 
= (int)wxINT32_SWAP_ON_BE( dbuf
[0] ); 
 251     /* some more sanity checks */ 
 252     if (((comp 
== BI_RLE4
) && (bpp 
!= 4)) || 
 253         ((comp 
== BI_RLE8
) && (bpp 
!= 8)) || 
 254         ((comp 
== BI_BITFIELDS
) && (bpp 
!= 16 && bpp 
!= 32))) 
 257             wxLogError( _("BMP: Encoding doesn't match bitdepth.") ); 
 262         cmap 
= (struct _cmap 
*)malloc(sizeof(struct _cmap
) * ncolors
); 
 266                 wxLogError( _("BMP: Couldn't allocate memory.") ); 
 273     image
->Create( width
, height 
); 
 274     unsigned char *ptr 
= image
->GetData(); 
 278             wxLogError( _("BMP: Couldn't allocate memory.") ); 
 285      * Reading the palette, if it exists. 
 287     if (bpp 
< 16 && ncolors 
!= 0) 
 289         unsigned char* r 
= new unsigned char[ncolors
]; 
 290         unsigned char* g 
= new unsigned char[ncolors
]; 
 291         unsigned char* b 
= new unsigned char[ncolors
]; 
 292         for (int j 
= 0; j 
< ncolors
; j
++) 
 294             stream
.Read( bbuf
, 4 ); 
 303         // Set the palette for the wxImage 
 304         image
->SetPalette(wxPalette(ncolors
, r
, g
, b
)); 
 310     else if (bpp 
== 16 || bpp 
== 32) 
 312         if (comp 
== BI_BITFIELDS
) 
 315             stream
.Read( dbuf
, 4 * 3 ); 
 316             bmask 
= wxINT32_SWAP_ON_BE( dbuf
[0] ); 
 317             gmask 
= wxINT32_SWAP_ON_BE( dbuf
[1] ); 
 318             rmask 
= wxINT32_SWAP_ON_BE( dbuf
[2] ); 
 319             /* find shift amount.. ugly, but i can't think of a better way */ 
 320             for (bit 
= 0; bit 
< bpp
; bit
++) 
 322                 if (bmask 
& (1 << bit
)) 
 324                 if (gmask 
& (1 << bit
)) 
 326                 if (rmask 
& (1 << bit
)) 
 351      * Reading the image data 
 353     stream
.SeekI( start_offset 
+ offset 
); 
 354     unsigned char *data 
= ptr
; 
 356     /* set the whole image to the background color */ 
 357     if (bpp 
< 16 && (comp 
== BI_RLE4 
|| comp 
== BI_RLE8
)) 
 359         for (int i 
= 0; i 
< width 
* height
; i
++) 
 370     int linesize 
= ((width 
* bpp 
+ 31) / 32) * 4; 
 372     /* BMPs are stored upside down */ 
 373     for (line 
= (height 
- 1); line 
>= 0; line
--) 
 376         for (column 
= 0; column 
< width
;) 
 382                 aByte 
= stream
.GetC(); 
 386                     for (bit 
= 0; bit 
< 8; bit
++) 
 388                         index 
= ((aByte 
& (0x80 >> bit
)) ? 1 : 0); 
 389                         ptr
[poffset
] = cmap
[index
].r
; 
 390                         ptr
[poffset 
+ 1] = cmap
[index
].g
; 
 391                         ptr
[poffset 
+ 2] = cmap
[index
].b
; 
 400                             wxLogError( _("BMP: Cannot deal with 4bit encoded yet.") ); 
 408                         for (nibble 
= 0; nibble 
< 2; nibble
++) 
 410                             index 
= ((aByte 
& (0xF0 >> nibble 
* 4)) >> (!nibble 
* 4)); 
 413                             ptr
[poffset
] = cmap
[index
].r
; 
 414                             ptr
[poffset 
+ 1] = cmap
[index
].g
; 
 415                             ptr
[poffset 
+ 2] = cmap
[index
].b
; 
 426                         aByte 
= stream
.GetC(); 
 431                                 /* column = width; */ 
 440                                 aByte 
= stream
.GetC(); 
 442                                 linepos 
= column 
* bpp 
/ 8; 
 443                                 aByte 
= stream
.GetC(); 
 448                                 int absolute 
= aByte
; 
 449                                 for (int k 
= 0; k 
< absolute
; k
++) 
 452                                     aByte 
= stream
.GetC(); 
 453                                     ptr
[poffset    
] = cmap
[aByte
].r
; 
 454                                     ptr
[poffset 
+ 1] = cmap
[aByte
].g
; 
 455                                     ptr
[poffset 
+ 2] = cmap
[aByte
].b
; 
 459                                     aByte 
= stream
.GetC(); 
 464                             for (int l 
= 0; l 
< first
; l
++) 
 466                                 ptr
[poffset    
] = cmap
[aByte
].r
; 
 467                                 ptr
[poffset 
+ 1] = cmap
[aByte
].g
; 
 468                                 ptr
[poffset 
+ 2] = cmap
[aByte
].b
; 
 476                         ptr
[poffset    
] = cmap
[aByte
].r
; 
 477                         ptr
[poffset 
+ 1] = cmap
[aByte
].g
; 
 478                         ptr
[poffset 
+ 2] = cmap
[aByte
].b
; 
 480                         // linepos += size;    seems to be wrong, RR 
 486                    stream
.Read( &bbuf
, 3 ); 
 488                    ptr
[poffset    
] = (unsigned char)bbuf
[2]; 
 489                    ptr
[poffset 
+ 1] = (unsigned char)bbuf
[1]; 
 490                    ptr
[poffset 
+ 2] = (unsigned char)bbuf
[0]; 
 496                    stream
.Read( &aWord
, 2 ); 
 497                    aWord 
= wxUINT16_SWAP_ON_BE( aWord 
); 
 499                    temp 
= (aWord 
& rmask
) >> rshift
; 
 501                    temp 
= (aWord 
& gmask
) >> gshift
; 
 502                    ptr
[poffset 
+ 1] = temp
; 
 503                    temp 
= (aWord 
& bmask
) >> bshift
; 
 504                    ptr
[poffset 
+ 2] = temp
; 
 510                    stream
.Read( &aDword
, 4 ); 
 511                    aDword 
= wxINT32_SWAP_ON_BE( aDword 
); 
 513                    temp 
= (aDword 
& rmask
) >> rshift
; 
 515                    temp 
= (aDword 
& gmask
) >> gshift
; 
 516                    ptr
[poffset 
+ 1] = temp
; 
 517                    temp 
= (aDword 
& bmask
) >> bshift
; 
 518                    ptr
[poffset 
+ 2] = temp
; 
 522           while ((linepos 
< linesize
) && (comp 
!= 1) && (comp 
!= 2)) 
 524               stream
.Read( &aByte
, 1 ); 
 526               if (stream
.LastError() != wxStream_NOERROR
) 
 533      image
->SetMask( FALSE 
); 
 538 bool wxBMPHandler::DoCanRead( wxInputStream
& stream 
) 
 540     unsigned char hdr
[2]; 
 542     stream
.Read(&hdr
, 2); 
 543     stream
.SeekI(-2, wxFromCurrent
); 
 544     return (hdr
[0] == 'B' && hdr
[1] == 'M'); 
 547 #endif // wxUSE_STREAMS