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