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