]> git.saurik.com Git - wxWidgets.git/blob - src/common/imagbmp.cpp
* wxMemoryStreams updates
[wxWidgets.git] / src / common / imagbmp.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: imagbmp.cpp
3 // Purpose: wxImage BMP handler
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 /*
11 We don't put pragma implement in this file because it is already present in
12 src/common/image.cpp
13 */
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #include "wx/image.h"
23 #include "wx/bitmap.h"
24 #include "wx/debug.h"
25 #include "wx/log.h"
26 #include "wx/app.h"
27 #include "wx/filefn.h"
28 #include "wx/wfstream.h"
29 #include "wx/intl.h"
30 #include "wx/module.h"
31
32 // For memcpy
33 #include <string.h>
34
35 #ifdef __SALFORDC__
36 #ifdef FAR
37 #undef FAR
38 #endif
39 #endif
40
41 #ifdef __WXMSW__
42 #include <windows.h>
43 #endif
44
45 //-----------------------------------------------------------------------------
46 // wxBMPHandler
47 //-----------------------------------------------------------------------------
48
49 #if !USE_SHARED_LIBRARIES
50 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
51 #endif
52
53 #if wxUSE_STREAMS
54
55 #ifndef BI_RGB
56 #define BI_RGB 0
57 #define BI_RLE8 1
58 #define BI_RLE4 2
59 #endif
60
61 #ifndef BI_BITFIELDS
62 #define BI_BITFIELDS 3
63 #endif
64
65 #define poffset (line * width * 3 + column * 3)
66
67 bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
68 {
69 int rshift = 0, gshift = 0, bshift = 0;
70 wxUint8 aByte;
71 wxUint16 aWord;
72 wxInt32 dbuf[4], aDword,
73 rmask = 0, gmask = 0, bmask = 0;
74 wxInt8 bbuf[4];
75 struct _cmap {
76 unsigned char r, g, b;
77 } *cmap = NULL;
78
79 off_t start_offset = stream.TellI();
80
81 image->Destroy();
82
83 /*
84 * Read the BMP header
85 */
86
87 stream.Read( &bbuf, 2 );
88 stream.Read( dbuf, 4 * 4 );
89
90 wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
91 wxInt32 offset = wxINT32_SWAP_ON_BE( dbuf[2] );
92
93 stream.Read(dbuf, 4 * 2);
94 int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
95 int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
96 if (width > 32767)
97 {
98 wxLogError( _T("Image width > 32767 pixels for file.") );
99 return FALSE;
100 }
101 if (height > 32767)
102 {
103 wxLogError( _T("Image height > 32767 pixels for file.") );
104 return FALSE;
105 }
106
107 stream.Read( &aWord, 2 );
108 /*
109 TODO
110 int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
111 */
112 stream.Read( &aWord, 2 );
113 int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
114 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
115 {
116 wxLogError( _T("unknown bitdepth in file.") );
117 return FALSE;
118 }
119
120 stream.Read( dbuf, 4 * 4 );
121 int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
122 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
123 {
124 wxLogError( _T("unknown encoding in Windows BMP file.") );
125 return FALSE;
126 }
127
128 stream.Read( dbuf, 4 * 2 );
129 int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
130 if (ncolors == 0)
131 ncolors = 1 << bpp;
132 /* some more sanity checks */
133 if (((comp == BI_RLE4) && (bpp != 4)) ||
134 ((comp == BI_RLE8) && (bpp != 8)) ||
135 ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
136 {
137 wxLogError( _T("encoding of BMP doesn't match bitdepth.") );
138 return FALSE;
139 }
140 if (bpp < 16)
141 {
142 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
143 if (!cmap)
144 {
145 wxLogError( _T("Cannot allocate RAM for color map in BMP file.") );
146 return FALSE;
147 }
148 }
149 else
150 cmap = NULL;
151
152 image->Create( width, height );
153 unsigned char *ptr = image->GetData();
154 if (!ptr)
155 {
156 wxLogError( _T("Cannot allocate RAM for RGB data in file.") );
157 if (cmap)
158 free(cmap);
159 return FALSE;
160 }
161
162 /*
163 * Reading the palette, if it exists.
164 */
165 if (bpp < 16 && ncolors != 0)
166 {
167 for (int j = 0; j < ncolors; j++)
168 {
169 stream.Read( bbuf, 4 );
170 cmap[j].b = bbuf[0];
171 cmap[j].g = bbuf[1];
172 cmap[j].r = bbuf[2];
173 }
174 }
175 else if (bpp == 16 || bpp == 32)
176 {
177 if (comp == BI_BITFIELDS)
178 {
179 int bit = 0;
180 stream.Read( dbuf, 4 * 3 );
181 bmask = wxINT32_SWAP_ON_BE( dbuf[0] );
182 gmask = wxINT32_SWAP_ON_BE( dbuf[1] );
183 rmask = wxINT32_SWAP_ON_BE( dbuf[2] );
184 /* find shift amount.. ugly, but i can't think of a better way */
185 for (bit = 0; bit < bpp; bit++)
186 {
187 if (bmask & (1 << bit))
188 bshift = bit;
189 if (gmask & (1 << bit))
190 gshift = bit;
191 if (rmask & (1 << bit))
192 rshift = bit;
193 }
194 }
195 else if (bpp == 16)
196 {
197 rmask = 0x7C00;
198 gmask = 0x03E0;
199 bmask = 0x001F;
200 rshift = 10;
201 gshift = 5;
202 bshift = 0;
203 }
204 else if (bpp == 32)
205 {
206 rmask = 0x00FF0000;
207 gmask = 0x0000FF00;
208 bmask = 0x000000FF;
209 rshift = 16;
210 gshift = 8;
211 bshift = 0;
212 }
213 }
214
215 /*
216 * Reading the image data
217 */
218 stream.SeekI( start_offset + offset );
219 unsigned char *data = ptr;
220
221 /* set the whole image to the background color */
222 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
223 {
224 for (int i = 0; i < width * height; i++)
225 {
226 *ptr++ = cmap[0].r;
227 *ptr++ = cmap[0].g;
228 *ptr++ = cmap[0].b;
229 }
230 ptr = data;
231 }
232
233 int line = 0;
234 int column = 0;
235 int linesize = ((width * bpp + 31) / 32) * 4;
236
237 /* BMPs are stored upside down */
238 for (line = (height - 1); line >= 0; line--)
239 {
240 int linepos = 0;
241 for (column = 0; column < width;)
242 {
243 if (bpp < 16)
244 {
245 int index = 0;
246 linepos++;
247 aByte = stream.GetC();
248 if (bpp == 1)
249 {
250 int bit = 0;
251 for (bit = 0; bit < 8; bit++)
252 {
253 index = ((aByte & (0x80 >> bit)) ? 1 : 0);
254 ptr[poffset] = cmap[index].r;
255 ptr[poffset + 1] = cmap[index].g;
256 ptr[poffset + 2] = cmap[index].b;
257 column++;
258 }
259 }
260 else if (bpp == 4)
261 {
262 if (comp == BI_RLE4)
263 {
264 wxLogError( _T("Can't deal with 4bit encoded yet.") );
265 image->Destroy();
266 free(cmap);
267 return FALSE;
268 }
269 else
270 {
271 int nibble = 0;
272 for (nibble = 0; nibble < 2; nibble++)
273 {
274 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
275 if (index >= 16)
276 index = 15;
277 ptr[poffset] = cmap[index].r;
278 ptr[poffset + 1] = cmap[index].g;
279 ptr[poffset + 2] = cmap[index].b;
280 column++;
281 }
282 }
283 }
284 else if (bpp == 8)
285 {
286 if (comp == BI_RLE8)
287 {
288 unsigned char first;
289 first = aByte;
290 aByte = stream.GetC();
291 if (first == 0)
292 {
293 if (aByte == 0)
294 {
295 /* column = width; */
296 }
297 else if (aByte == 1)
298 {
299 column = width;
300 line = -1;
301 }
302 else if (aByte == 2)
303 {
304 aByte = stream.GetC();
305 column += aByte;
306 linepos = column * bpp / 8;
307 aByte = stream.GetC();
308 line += aByte;
309 }
310 else
311 {
312 int absolute = aByte;
313 for (int k = 0; k < absolute; k++)
314 {
315 linepos++;
316 aByte = stream.GetC();
317 ptr[poffset ] = cmap[aByte].r;
318 ptr[poffset + 1] = cmap[aByte].g;
319 ptr[poffset + 2] = cmap[aByte].b;
320 column++;
321 }
322 if (absolute & 0x01)
323 aByte = stream.GetC();
324 }
325 }
326 else
327 {
328 for (int l = 0; l < first; l++)
329 {
330 ptr[poffset ] = cmap[aByte].r;
331 ptr[poffset + 1] = cmap[aByte].g;
332 ptr[poffset + 2] = cmap[aByte].b;
333 column++;
334 linepos++;
335 }
336 }
337 }
338 else
339 {
340 ptr[poffset ] = cmap[aByte].r;
341 ptr[poffset + 1] = cmap[aByte].g;
342 ptr[poffset + 2] = cmap[aByte].b;
343 column++;
344 linepos += size;
345 }
346 }
347 }
348 else if (bpp == 24)
349 {
350 stream.Read( &bbuf, 3 );
351 linepos += 3;
352 ptr[poffset ] = (unsigned char)bbuf[2];
353 ptr[poffset + 1] = (unsigned char)bbuf[1];
354 ptr[poffset + 2] = (unsigned char)bbuf[0];
355 column++;
356 }
357 else if (bpp == 16)
358 {
359 unsigned char temp;
360 stream.Read( &aWord, 2 );
361 aWord = wxUINT16_SWAP_ON_BE( aWord );
362 linepos += 2;
363 temp = (aWord & rmask) >> rshift;
364 ptr[poffset] = temp;
365 temp = (aWord & gmask) >> gshift;
366 ptr[poffset + 1] = temp;
367 temp = (aWord & bmask) >> gshift;
368 ptr[poffset + 2] = temp;
369 column++;
370 }
371 else
372 {
373 unsigned char temp;
374 stream.Read( &aDword, 4 );
375 aDword = wxINT32_SWAP_ON_BE( aDword );
376 linepos += 4;
377 temp = (aDword & rmask) >> rshift;
378 ptr[poffset] = temp;
379 temp = (aDword & gmask) >> gshift;
380 ptr[poffset + 1] = temp;
381 temp = (aDword & bmask) >> bshift;
382 ptr[poffset + 2] = temp;
383 column++;
384 }
385 }
386 while ((linepos < linesize) && (comp != 1) && (comp != 2))
387 {
388 stream.Read( &aByte, 1 );
389 linepos += 1;
390 if (stream.LastError() != wxStream_NOERROR)
391 break;
392 }
393 }
394 if (cmap)
395 free(cmap);
396
397 image->SetMask( FALSE );
398
399 return TRUE;
400 }
401
402 #endif // wxUSE_STREAMS
403
404