]> git.saurik.com Git - wxWidgets.git/blob - src/common/imagbmp.cpp
doc view code inteprets wxSTREAM_EOF as correct,
[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, bool verbose, int WXUNUSED(index) )
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 #if 0 // unused
91 wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
92 #endif
93 wxInt32 offset = wxINT32_SWAP_ON_BE( dbuf[2] );
94
95 stream.Read(dbuf, 4 * 2);
96 int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
97 int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
98 if (width > 32767)
99 {
100 if (verbose)
101 wxLogError( _("BMP: Image width > 32767 pixels for file.") );
102 return FALSE;
103 }
104 if (height > 32767)
105 {
106 if (verbose)
107 wxLogError( _("BMP: Image height > 32767 pixels for file.") );
108 return FALSE;
109 }
110
111 stream.Read( &aWord, 2 );
112 /*
113 TODO
114 int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
115 */
116 stream.Read( &aWord, 2 );
117 int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
118 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
119 {
120 if (verbose)
121 wxLogError( _("BMP: Unknown bitdepth in file.") );
122 return FALSE;
123 }
124
125 stream.Read( dbuf, 4 * 4 );
126 int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
127 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
128 {
129 if (verbose)
130 wxLogError( _("BMP: Unknown encoding in file.") );
131 return FALSE;
132 }
133
134 stream.Read( dbuf, 4 * 2 );
135 int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
136 if (ncolors == 0)
137 ncolors = 1 << bpp;
138 /* some more sanity checks */
139 if (((comp == BI_RLE4) && (bpp != 4)) ||
140 ((comp == BI_RLE8) && (bpp != 8)) ||
141 ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
142 {
143 if (verbose)
144 wxLogError( _("BMP: Encoding doesn't match bitdepth.") );
145 return FALSE;
146 }
147 if (bpp < 16)
148 {
149 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
150 if (!cmap)
151 {
152 if (verbose)
153 wxLogError( _("BMP: Couldn't allocate memory.") );
154 return FALSE;
155 }
156 }
157 else
158 cmap = NULL;
159
160 image->Create( width, height );
161 unsigned char *ptr = image->GetData();
162 if (!ptr)
163 {
164 if (verbose)
165 wxLogError( _("BMP: Couldn't allocate memory.") );
166 if (cmap)
167 free(cmap);
168 return FALSE;
169 }
170
171 /*
172 * Reading the palette, if it exists.
173 */
174 if (bpp < 16 && ncolors != 0)
175 {
176 for (int j = 0; j < ncolors; j++)
177 {
178 stream.Read( bbuf, 4 );
179 cmap[j].b = bbuf[0];
180 cmap[j].g = bbuf[1];
181 cmap[j].r = bbuf[2];
182 }
183 }
184 else if (bpp == 16 || bpp == 32)
185 {
186 if (comp == BI_BITFIELDS)
187 {
188 int bit = 0;
189 stream.Read( dbuf, 4 * 3 );
190 bmask = wxINT32_SWAP_ON_BE( dbuf[0] );
191 gmask = wxINT32_SWAP_ON_BE( dbuf[1] );
192 rmask = wxINT32_SWAP_ON_BE( dbuf[2] );
193 /* find shift amount.. ugly, but i can't think of a better way */
194 for (bit = 0; bit < bpp; bit++)
195 {
196 if (bmask & (1 << bit))
197 bshift = bit;
198 if (gmask & (1 << bit))
199 gshift = bit;
200 if (rmask & (1 << bit))
201 rshift = bit;
202 }
203 }
204 else if (bpp == 16)
205 {
206 rmask = 0x7C00;
207 gmask = 0x03E0;
208 bmask = 0x001F;
209 rshift = 10;
210 gshift = 5;
211 bshift = 0;
212 }
213 else if (bpp == 32)
214 {
215 rmask = 0x00FF0000;
216 gmask = 0x0000FF00;
217 bmask = 0x000000FF;
218 rshift = 16;
219 gshift = 8;
220 bshift = 0;
221 }
222 }
223
224 /*
225 * Reading the image data
226 */
227 stream.SeekI( start_offset + offset );
228 unsigned char *data = ptr;
229
230 /* set the whole image to the background color */
231 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
232 {
233 for (int i = 0; i < width * height; i++)
234 {
235 *ptr++ = cmap[0].r;
236 *ptr++ = cmap[0].g;
237 *ptr++ = cmap[0].b;
238 }
239 ptr = data;
240 }
241
242 int line = 0;
243 int column = 0;
244 int linesize = ((width * bpp + 31) / 32) * 4;
245
246 /* BMPs are stored upside down */
247 for (line = (height - 1); line >= 0; line--)
248 {
249 int linepos = 0;
250 for (column = 0; column < width;)
251 {
252 if (bpp < 16)
253 {
254 int index = 0;
255 linepos++;
256 aByte = stream.GetC();
257 if (bpp == 1)
258 {
259 int bit = 0;
260 for (bit = 0; bit < 8; bit++)
261 {
262 index = ((aByte & (0x80 >> bit)) ? 1 : 0);
263 ptr[poffset] = cmap[index].r;
264 ptr[poffset + 1] = cmap[index].g;
265 ptr[poffset + 2] = cmap[index].b;
266 column++;
267 }
268 }
269 else if (bpp == 4)
270 {
271 if (comp == BI_RLE4)
272 {
273 if (verbose)
274 wxLogError( _("BMP: Cannot deal with 4bit encoded yet.") );
275 image->Destroy();
276 free(cmap);
277 return FALSE;
278 }
279 else
280 {
281 int nibble = 0;
282 for (nibble = 0; nibble < 2; nibble++)
283 {
284 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
285 if (index >= 16)
286 index = 15;
287 ptr[poffset] = cmap[index].r;
288 ptr[poffset + 1] = cmap[index].g;
289 ptr[poffset + 2] = cmap[index].b;
290 column++;
291 }
292 }
293 }
294 else if (bpp == 8)
295 {
296 if (comp == BI_RLE8)
297 {
298 unsigned char first;
299 first = aByte;
300 aByte = stream.GetC();
301 if (first == 0)
302 {
303 if (aByte == 0)
304 {
305 /* column = width; */
306 }
307 else if (aByte == 1)
308 {
309 column = width;
310 line = -1;
311 }
312 else if (aByte == 2)
313 {
314 aByte = stream.GetC();
315 column += aByte;
316 linepos = column * bpp / 8;
317 aByte = stream.GetC();
318 line += aByte;
319 }
320 else
321 {
322 int absolute = aByte;
323 for (int k = 0; k < absolute; k++)
324 {
325 linepos++;
326 aByte = stream.GetC();
327 ptr[poffset ] = cmap[aByte].r;
328 ptr[poffset + 1] = cmap[aByte].g;
329 ptr[poffset + 2] = cmap[aByte].b;
330 column++;
331 }
332 if (absolute & 0x01)
333 aByte = stream.GetC();
334 }
335 }
336 else
337 {
338 for (int l = 0; l < first; l++)
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++;
345 }
346 }
347 }
348 else
349 {
350 ptr[poffset ] = cmap[aByte].r;
351 ptr[poffset + 1] = cmap[aByte].g;
352 ptr[poffset + 2] = cmap[aByte].b;
353 column++;
354 // linepos += size; seems to be wrong, RR
355 }
356 }
357 }
358 else if (bpp == 24)
359 {
360 stream.Read( &bbuf, 3 );
361 linepos += 3;
362 ptr[poffset ] = (unsigned char)bbuf[2];
363 ptr[poffset + 1] = (unsigned char)bbuf[1];
364 ptr[poffset + 2] = (unsigned char)bbuf[0];
365 column++;
366 }
367 else if (bpp == 16)
368 {
369 unsigned char temp;
370 stream.Read( &aWord, 2 );
371 aWord = wxUINT16_SWAP_ON_BE( aWord );
372 linepos += 2;
373 temp = (aWord & rmask) >> rshift;
374 ptr[poffset] = temp;
375 temp = (aWord & gmask) >> gshift;
376 ptr[poffset + 1] = temp;
377 temp = (aWord & bmask) >> bshift;
378 ptr[poffset + 2] = temp;
379 column++;
380 }
381 else
382 {
383 unsigned char temp;
384 stream.Read( &aDword, 4 );
385 aDword = wxINT32_SWAP_ON_BE( aDword );
386 linepos += 4;
387 temp = (aDword & rmask) >> rshift;
388 ptr[poffset] = temp;
389 temp = (aDword & gmask) >> gshift;
390 ptr[poffset + 1] = temp;
391 temp = (aDword & bmask) >> bshift;
392 ptr[poffset + 2] = temp;
393 column++;
394 }
395 }
396 while ((linepos < linesize) && (comp != 1) && (comp != 2))
397 {
398 stream.Read( &aByte, 1 );
399 linepos += 1;
400 if (stream.LastError() != wxStream_NOERROR)
401 break;
402 }
403 }
404 if (cmap)
405 free(cmap);
406
407 image->SetMask( FALSE );
408
409 return TRUE;
410 }
411
412 bool wxBMPHandler::DoCanRead( wxInputStream& stream )
413 {
414 unsigned char hdr[2];
415
416 stream.Read(&hdr, 2);
417 stream.SeekI(-2, wxFromCurrent);
418 return (hdr[0] == 'B' && hdr[1] == 'M');
419 }
420
421 #endif // wxUSE_STREAMS
422
423