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