]>
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