]>
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"
25 #include "wx/imagbmp.h"
26 #include "wx/bitmap.h"
30 #include "wx/filefn.h"
31 #include "wx/wfstream.h"
33 #include "wx/module.h"
48 //-----------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------
52 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler
,wxImageHandler
)
58 bool wxBMPHandler::SaveFile(wxImage
*image
,
59 wxOutputStream
& stream
,
62 wxCHECK_MSG( image
, FALSE
, _T("invalid pointer in wxBMPHandler::SaveFile") );
66 if (verbose
) wxLogError(_("BMP: Couldn't save invalid image."));
70 unsigned width
= image
->GetWidth();
71 unsigned row_width
= width
* 3 +
72 (((width
% 4) == 0) ? 0 : (4 - (width
* 3) % 4));
73 // each row must be aligned to dwords
77 wxUint16 magic
; // format magic, always 'BM'
78 wxUint32 filesize
; // total file size, inc. headers
79 wxUint32 reserved
; // for future use
80 wxUint32 data_offset
; // image data offset in the file
83 wxUint32 bih_size
; // 2nd part's size
84 wxUint32 width
, height
; // bitmap's dimensions
85 wxUint16 planes
; // num of planes
86 wxUint16 bpp
; // bits per pixel
87 wxUint32 compression
; // compression method
88 wxUint32 size_of_bmp
; // size of the bitmap
89 wxUint32 h_res
, v_res
; // image resolution in dpi
90 wxUint32 num_clrs
; // number of colors used
91 wxUint32 num_signif_clrs
;// number of significant colors
93 wxUint32 hdr_size
= 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/;
95 hdr
.magic
= wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/);
96 hdr
.filesize
= wxUINT32_SWAP_ON_BE(
98 row_width
* image
->GetHeight()
101 hdr
.data_offset
= wxUINT32_SWAP_ON_BE(hdr_size
);
103 hdr
.bih_size
= wxUINT32_SWAP_ON_BE(hdr_size
- 14);
104 hdr
.width
= wxUINT32_SWAP_ON_BE(image
->GetWidth());
105 hdr
.height
= wxUINT32_SWAP_ON_BE(image
->GetHeight());
106 hdr
.planes
= wxUINT16_SWAP_ON_BE(1); // always 1 plane
107 hdr
.bpp
= wxUINT16_SWAP_ON_BE(24); // always TrueColor
108 hdr
.compression
= 0; // RGB uncompressed
109 hdr
.size_of_bmp
= wxUINT32_SWAP_ON_BE(row_width
* image
->GetHeight());
110 hdr
.h_res
= hdr
.v_res
= wxUINT32_SWAP_ON_BE(72); // 72dpi is standard
111 hdr
.num_clrs
= 0; // maximal possible = 2^24
112 hdr
.num_signif_clrs
= 0; // all colors are significant
114 if (// VS: looks ugly but compilers tend to do ugly things with structs,
115 // like aligning hdr.filesize's ofset to dword :(
116 // VZ: we should add padding then...
117 !stream
.Write(&hdr
.magic
, 2) ||
118 !stream
.Write(&hdr
.filesize
, 4) ||
119 !stream
.Write(&hdr
.reserved
, 4) ||
120 !stream
.Write(&hdr
.data_offset
, 4) ||
121 !stream
.Write(&hdr
.bih_size
, 4) ||
122 !stream
.Write(&hdr
.width
, 4) ||
123 !stream
.Write(&hdr
.height
, 4) ||
124 !stream
.Write(&hdr
.planes
, 2) ||
125 !stream
.Write(&hdr
.bpp
, 2) ||
126 !stream
.Write(&hdr
.compression
, 4) ||
127 !stream
.Write(&hdr
.size_of_bmp
, 4) ||
128 !stream
.Write(&hdr
.h_res
, 4) ||
129 !stream
.Write(&hdr
.v_res
, 4) ||
130 !stream
.Write(&hdr
.num_clrs
, 4) ||
131 !stream
.Write(&hdr
.num_signif_clrs
, 4)
135 wxLogError(_("BMP: Couldn't write the file header."));
139 wxUint8
*data
= (wxUint8
*) image
->GetData();
140 wxUint8
*buffer
= new wxUint8
[row_width
];
142 memset(buffer
, 0, row_width
);
145 for (y
= image
->GetHeight() -1 ; y
>= 0; y
--)
147 memcpy(buffer
, data
+ y
* 3 * width
, 3 * width
);
148 for (x
= 0; x
< width
; x
++)
150 tmpvar
= buffer
[3 * x
+ 0];
151 buffer
[3 * x
+ 0] = buffer
[3 * x
+ 2];
152 buffer
[3 * x
+ 2] = tmpvar
;
155 if (!stream
.Write(buffer
, row_width
))
158 wxLogError(_("BMP: Couldn't write data."));
178 #define BI_BITFIELDS 3
181 #define poffset (line * width * 3 + column * 3)
183 bool wxBMPHandler::LoadFile( wxImage
*image
, wxInputStream
& stream
, bool verbose
, int WXUNUSED(index
) )
185 int rshift
= 0, gshift
= 0, bshift
= 0;
188 wxInt32 dbuf
[4], aDword
,
189 rmask
= 0, gmask
= 0, bmask
= 0;
192 unsigned char r
, g
, b
;
195 off_t start_offset
= stream
.TellI();
196 if (start_offset
== wxInvalidOffset
) start_offset
= 0;
201 * Read the BMP header
204 stream
.Read( &bbuf
, 2 );
205 stream
.Read( dbuf
, 4 * 4 );
208 wxInt32 size
= wxINT32_SWAP_ON_BE( dbuf
[0] );
210 wxInt32 offset
= wxINT32_SWAP_ON_BE( dbuf
[2] );
212 stream
.Read(dbuf
, 4 * 2);
213 int width
= (int)wxINT32_SWAP_ON_BE( dbuf
[0] );
214 int height
= (int)wxINT32_SWAP_ON_BE( dbuf
[1] );
218 wxLogError( _("BMP: Image width > 32767 pixels for file.") );
224 wxLogError( _("BMP: Image height > 32767 pixels for file.") );
228 stream
.Read( &aWord
, 2 );
231 int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
233 stream
.Read( &aWord
, 2 );
234 int bpp
= (int)wxUINT16_SWAP_ON_BE( aWord
);
235 if (bpp
!= 1 && bpp
!= 4 && bpp
!= 8 && bpp
!= 16 && bpp
!= 24 && bpp
!= 32)
238 wxLogError( _("BMP: Unknown bitdepth in file.") );
242 stream
.Read( dbuf
, 4 * 4 );
243 int comp
= (int)wxINT32_SWAP_ON_BE( dbuf
[0] );
244 if (comp
!= BI_RGB
&& comp
!= BI_RLE4
&& comp
!= BI_RLE8
&& comp
!= BI_BITFIELDS
)
247 wxLogError( _("BMP: Unknown encoding in file.") );
251 stream
.Read( dbuf
, 4 * 2 );
252 int ncolors
= (int)wxINT32_SWAP_ON_BE( dbuf
[0] );
255 /* some more sanity checks */
256 if (((comp
== BI_RLE4
) && (bpp
!= 4)) ||
257 ((comp
== BI_RLE8
) && (bpp
!= 8)) ||
258 ((comp
== BI_BITFIELDS
) && (bpp
!= 16 && bpp
!= 32)))
261 wxLogError( _("BMP: Encoding doesn't match bitdepth.") );
266 cmap
= (struct _cmap
*)malloc(sizeof(struct _cmap
) * ncolors
);
270 wxLogError( _("BMP: Couldn't allocate memory.") );
277 image
->Create( width
, height
);
278 unsigned char *ptr
= image
->GetData();
282 wxLogError( _("BMP: Couldn't allocate memory.") );
289 * Reading the palette, if it exists.
291 if (bpp
< 16 && ncolors
!= 0)
293 unsigned char* r
= new unsigned char[ncolors
];
294 unsigned char* g
= new unsigned char[ncolors
];
295 unsigned char* b
= new unsigned char[ncolors
];
296 for (int j
= 0; j
< ncolors
; j
++)
298 stream
.Read( bbuf
, 4 );
307 // Set the palette for the wxImage
308 image
->SetPalette(wxPalette(ncolors
, r
, g
, b
));
314 else if (bpp
== 16 || bpp
== 32)
316 if (comp
== BI_BITFIELDS
)
319 stream
.Read( dbuf
, 4 * 3 );
320 bmask
= wxINT32_SWAP_ON_BE( dbuf
[0] );
321 gmask
= wxINT32_SWAP_ON_BE( dbuf
[1] );
322 rmask
= wxINT32_SWAP_ON_BE( dbuf
[2] );
323 /* find shift amount.. ugly, but i can't think of a better way */
324 for (bit
= 0; bit
< bpp
; bit
++)
326 if (bmask
& (1 << bit
))
328 if (gmask
& (1 << bit
))
330 if (rmask
& (1 << bit
))
355 * Reading the image data
357 stream
.SeekI( start_offset
+ offset
);
358 unsigned char *data
= ptr
;
360 /* set the whole image to the background color */
361 if (bpp
< 16 && (comp
== BI_RLE4
|| comp
== BI_RLE8
))
363 for (int i
= 0; i
< width
* height
; i
++)
374 int linesize
= ((width
* bpp
+ 31) / 32) * 4;
376 /* BMPs are stored upside down */
377 for (line
= (height
- 1); line
>= 0; line
--)
380 for (column
= 0; column
< width
;)
386 aByte
= stream
.GetC();
390 for (bit
= 0; bit
< 8 && column
< width
; bit
++)
392 index
= ((aByte
& (0x80 >> bit
)) ? 1 : 0);
393 ptr
[poffset
] = cmap
[index
].r
;
394 ptr
[poffset
+ 1] = cmap
[index
].g
;
395 ptr
[poffset
+ 2] = cmap
[index
].b
;
404 wxLogError( _("BMP: Cannot deal with 4bit encoded yet.") );
412 for (nibble
= 0; nibble
< 2 && column
< width
; nibble
++)
414 index
= ((aByte
& (0xF0 >> nibble
* 4)) >> (!nibble
* 4));
417 ptr
[poffset
] = cmap
[index
].r
;
418 ptr
[poffset
+ 1] = cmap
[index
].g
;
419 ptr
[poffset
+ 2] = cmap
[index
].b
;
430 aByte
= stream
.GetC();
435 /* column = width; */
444 aByte
= stream
.GetC();
446 linepos
= column
* bpp
/ 8;
447 aByte
= stream
.GetC();
452 int absolute
= aByte
;
453 for (int k
= 0; k
< absolute
; k
++)
456 aByte
= stream
.GetC();
457 ptr
[poffset
] = cmap
[aByte
].r
;
458 ptr
[poffset
+ 1] = cmap
[aByte
].g
;
459 ptr
[poffset
+ 2] = cmap
[aByte
].b
;
463 aByte
= stream
.GetC();
468 for (int l
= 0; l
< first
&& column
< width
; l
++)
470 ptr
[poffset
] = cmap
[aByte
].r
;
471 ptr
[poffset
+ 1] = cmap
[aByte
].g
;
472 ptr
[poffset
+ 2] = cmap
[aByte
].b
;
480 ptr
[poffset
] = cmap
[aByte
].r
;
481 ptr
[poffset
+ 1] = cmap
[aByte
].g
;
482 ptr
[poffset
+ 2] = cmap
[aByte
].b
;
484 // linepos += size; seems to be wrong, RR
490 stream
.Read( &bbuf
, 3 );
492 ptr
[poffset
] = (unsigned char)bbuf
[2];
493 ptr
[poffset
+ 1] = (unsigned char)bbuf
[1];
494 ptr
[poffset
+ 2] = (unsigned char)bbuf
[0];
500 stream
.Read( &aWord
, 2 );
501 aWord
= wxUINT16_SWAP_ON_BE( aWord
);
503 temp
= (aWord
& rmask
) >> rshift
;
505 temp
= (aWord
& gmask
) >> gshift
;
506 ptr
[poffset
+ 1] = temp
;
507 temp
= (aWord
& bmask
) >> bshift
;
508 ptr
[poffset
+ 2] = temp
;
514 stream
.Read( &aDword
, 4 );
515 aDword
= wxINT32_SWAP_ON_BE( aDword
);
517 temp
= (aDword
& rmask
) >> rshift
;
519 temp
= (aDword
& gmask
) >> gshift
;
520 ptr
[poffset
+ 1] = temp
;
521 temp
= (aDword
& bmask
) >> bshift
;
522 ptr
[poffset
+ 2] = temp
;
526 while ((linepos
< linesize
) && (comp
!= 1) && (comp
!= 2))
528 stream
.Read( &aByte
, 1 );
530 if (stream
.LastError() != wxStream_NOERROR
)
537 image
->SetMask( FALSE
);
542 bool wxBMPHandler::DoCanRead( wxInputStream
& stream
)
544 unsigned char hdr
[2];
546 stream
.Read(&hdr
, 2);
547 stream
.SeekI(-2, wxFromCurrent
);
548 return (hdr
[0] == 'B' && hdr
[1] == 'M');
551 #endif // wxUSE_STREAMS
553 #endif // wxUSE_IMAGE