]> git.saurik.com Git - wxWidgets.git/blob - src/common/imagbmp.cpp
added compression ratio argument to wxZlibOutputStream ctor
[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 #ifdef __GNUG__
11 #pragma implementation "imagbmp.h"
12 #endif
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
21 #include "wx/imagbmp.h"
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
48 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
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
64 bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
65 {
66 int rshift = 0, gshift = 0, bshift = 0;
67 wxUint8 aByte;
68 wxUint16 aWord;
69 wxInt32 dbuf[4], aDword,
70 rmask = 0, gmask = 0, bmask = 0;
71 wxInt8 bbuf[4];
72 struct _cmap {
73 unsigned char r, g, b;
74 } *cmap = NULL;
75
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
87 #if 0 // unused
88 wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
89 #endif
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 {
97 if (verbose)
98 wxLogError( _("BMP: Image width > 32767 pixels for file.") );
99 return FALSE;
100 }
101 if (height > 32767)
102 {
103 if (verbose)
104 wxLogError( _("BMP: Image height > 32767 pixels for file.") );
105 return FALSE;
106 }
107
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 {
117 if (verbose)
118 wxLogError( _("BMP: 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 if (verbose)
127 wxLogError( _("BMP: Unknown encoding in file.") );
128 return FALSE;
129 }
130
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 */
136 if (((comp == BI_RLE4) && (bpp != 4)) ||
137 ((comp == BI_RLE8) && (bpp != 8)) ||
138 ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
139 {
140 if (verbose)
141 wxLogError( _("BMP: Encoding doesn't match bitdepth.") );
142 return FALSE;
143 }
144 if (bpp < 16)
145 {
146 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
147 if (!cmap)
148 {
149 if (verbose)
150 wxLogError( _("BMP: Couldn't allocate memory.") );
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 {
161 if (verbose)
162 wxLogError( _("BMP: Couldn't allocate memory.") );
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 }
238
239 int line = 0;
240 int column = 0;
241 int linesize = ((width * bpp + 31) / 32) * 4;
242
243 /* BMPs are stored upside down */
244 for (line = (height - 1); line >= 0; line--)
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 {
270 if (verbose)
271 wxLogError( _("BMP: Cannot deal with 4bit encoded yet.") );
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++;
351 // linepos += size; seems to be wrong, 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 );
368 aWord = wxUINT16_SWAP_ON_BE( aWord );
369 linepos += 2;
370 temp = (aWord & rmask) >> rshift;
371 ptr[poffset] = temp;
372 temp = (aWord & gmask) >> gshift;
373 ptr[poffset + 1] = temp;
374 temp = (aWord & bmask) >> bshift;
375 ptr[poffset + 2] = temp;
376 column++;
377 }
378 else
379 {
380 unsigned char temp;
381 stream.Read( &aDword, 4 );
382 aDword = wxINT32_SWAP_ON_BE( aDword );
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 }
401 if (cmap)
402 free(cmap);
403
404 image->SetMask( FALSE );
405
406 return TRUE;
407 }
408
409 bool wxBMPHandler::DoCanRead( wxInputStream& stream )
410 {
411 unsigned char hdr[2];
412
413 stream.Read(&hdr, 2);
414 stream.SeekI(-2, wxFromCurrent);
415 return (hdr[0] == 'B' && hdr[1] == 'M');
416 }
417
418 #endif // wxUSE_STREAMS
419
420