]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagbmp.cpp
added wxApp::Yield()
[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
c96ea657
VS
21#include "wx/defs.h"
22
23#if wxUSE_IMAGE
24
8f493002 25#include "wx/imagbmp.h"
e65ed37a
RR
26#include "wx/bitmap.h"
27#include "wx/debug.h"
28#include "wx/log.h"
29#include "wx/app.h"
30#include "wx/filefn.h"
31#include "wx/wfstream.h"
32#include "wx/intl.h"
33#include "wx/module.h"
1971d23c 34#include "wx/quantize.h"
e65ed37a
RR
35
36// For memcpy
37#include <string.h>
38
39#ifdef __SALFORDC__
40#ifdef FAR
41#undef FAR
42#endif
43#endif
44
45#ifdef __WXMSW__
46#include <windows.h>
47#endif
48
49//-----------------------------------------------------------------------------
50// wxBMPHandler
51//-----------------------------------------------------------------------------
52
e65ed37a 53IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
e65ed37a 54
f6bcfd97 55
e65ed37a
RR
56#if wxUSE_STREAMS
57
f6bcfd97
BP
58
59bool wxBMPHandler::SaveFile(wxImage *image,
60 wxOutputStream& stream,
61 bool verbose)
62{
63 wxCHECK_MSG( image, FALSE, _T("invalid pointer in wxBMPHandler::SaveFile") );
64
65 if (!image->Ok())
66 {
67 if (verbose) wxLogError(_("BMP: Couldn't save invalid image."));
68 return FALSE;
69 }
70
1971d23c
VZ
71 // get the format of the BMP file to save, else use 24bpp
72 unsigned format = wxBMP_24BPP;
73 if (image->HasOption(wxBMP_FORMAT))
74 format = image->GetOptionInt(wxBMP_FORMAT);
75
76 unsigned bpp; // # of bits per pixel
77 int palette_size; // # of color map entries, ie. 2^bpp colors
78
79 // set the bpp and appropriate palette_size, and do additional checks
80 if ((format == wxBMP_1BPP) || (format == wxBMP_1BPP_BW))
81 {
82 bpp = 1;
83 palette_size = 2;
84 }
85 else if (format == wxBMP_4BPP)
86 {
87 bpp = 4;
88 palette_size = 16;
89 }
90 else if ((format == wxBMP_8BPP) || (format == wxBMP_8BPP_GREY) ||
91 (format == wxBMP_8BPP_RED) || (format == wxBMP_8BPP_PALETTE))
92 {
93 // need to set a wxPalette to use this, HOW TO CHECK IF VALID, SIZE?
b11e8fb6
VZ
94 if ((format == wxBMP_8BPP_PALETTE)
95#if wxUSE_PALETTE
96 && !image->HasPalette()
97#endif // wxUSE_PALETTE
98 )
1971d23c
VZ
99 {
100 if (verbose)
101 wxLogError(_("BMP: wImage doesn't have own wxPalette."));
102 return FALSE;
103 }
104 bpp = 8;
105 palette_size = 256;
106 }
107 else // you get 24bpp
108 {
109 format = wxBMP_24BPP;
110 bpp = 24;
111 palette_size = 0;
112 }
113
f6bcfd97 114 unsigned width = image->GetWidth();
1971d23c
VZ
115 unsigned row_padding = (4 - int(width*bpp/8.0) % 4) % 4; // # bytes to pad to dword
116 unsigned row_width = int(width * bpp/8.0) + row_padding; // # of bytes per row
117
f6bcfd97
BP
118 struct
119 {
120 // BitmapHeader:
121 wxUint16 magic; // format magic, always 'BM'
122 wxUint32 filesize; // total file size, inc. headers
123 wxUint32 reserved; // for future use
124 wxUint32 data_offset; // image data offset in the file
33ac7e6f 125
f6bcfd97
BP
126 // BitmapInfoHeader:
127 wxUint32 bih_size; // 2nd part's size
128 wxUint32 width, height; // bitmap's dimensions
129 wxUint16 planes; // num of planes
130 wxUint16 bpp; // bits per pixel
131 wxUint32 compression; // compression method
132 wxUint32 size_of_bmp; // size of the bitmap
133 wxUint32 h_res, v_res; // image resolution in dpi
134 wxUint32 num_clrs; // number of colors used
135 wxUint32 num_signif_clrs;// number of significant colors
136 } hdr;
1971d23c 137
f6bcfd97
BP
138 wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/;
139
140 hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/);
1971d23c
VZ
141 hdr.filesize = wxUINT32_SWAP_ON_BE( hdr_size + palette_size*4 +
142 row_width * image->GetHeight() );
f6bcfd97 143 hdr.reserved = 0;
1971d23c 144 hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size + palette_size*4);
33ac7e6f 145
f6bcfd97
BP
146 hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14);
147 hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth());
148 hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight());
149 hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane
1971d23c 150 hdr.bpp = wxUINT16_SWAP_ON_BE(bpp);
f6bcfd97 151 hdr.compression = 0; // RGB uncompressed
33ac7e6f 152 hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight());
1971d23c
VZ
153 hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72); // 72dpi is standard
154 hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap
155 hdr.num_signif_clrs = 0; // all colors are significant
f6bcfd97
BP
156
157 if (// VS: looks ugly but compilers tend to do ugly things with structs,
158 // like aligning hdr.filesize's ofset to dword :(
159 // VZ: we should add padding then...
160 !stream.Write(&hdr.magic, 2) ||
161 !stream.Write(&hdr.filesize, 4) ||
162 !stream.Write(&hdr.reserved, 4) ||
163 !stream.Write(&hdr.data_offset, 4) ||
164 !stream.Write(&hdr.bih_size, 4) ||
165 !stream.Write(&hdr.width, 4) ||
166 !stream.Write(&hdr.height, 4) ||
167 !stream.Write(&hdr.planes, 2) ||
168 !stream.Write(&hdr.bpp, 2) ||
169 !stream.Write(&hdr.compression, 4) ||
170 !stream.Write(&hdr.size_of_bmp, 4) ||
171 !stream.Write(&hdr.h_res, 4) ||
172 !stream.Write(&hdr.v_res, 4) ||
173 !stream.Write(&hdr.num_clrs, 4) ||
174 !stream.Write(&hdr.num_signif_clrs, 4)
33ac7e6f 175 )
f6bcfd97
BP
176 {
177 if (verbose)
178 wxLogError(_("BMP: Couldn't write the file header."));
179 return FALSE;
180 }
181
1971d23c
VZ
182 wxPalette *palette = NULL; // entries for quantized images
183 wxUint8 *rgbquad = NULL; // for the RGBQUAD bytes for the colormap
184 wxImage *q_image = NULL; // destination for quantized image
185
186 // if <24bpp use quantization to reduce colors for *some* of the formats
187 if ( (format == wxBMP_1BPP) || (format == wxBMP_4BPP) ||
188 (format == wxBMP_8BPP) || (format == wxBMP_8BPP_PALETTE))
189 {
190 // make a new palette and quantize the image
191 if (format != wxBMP_8BPP_PALETTE)
192 {
193 q_image = new wxImage();
194
195 // I get a delete error using Quantize when desired colors > 236
196 int quantize = ((palette_size > 236) ? 236 : palette_size);
197 // fill the destination too, it gives much nicer 4bpp images
198 wxQuantize::Quantize( *image, *q_image, &palette, quantize, 0,
199 wxQUANTIZE_FILL_DESTINATION_IMAGE );
200 }
201 else
202 {
b11e8fb6 203#if wxUSE_PALETTE
1971d23c 204 palette = new wxPalette(image->GetPalette());
b11e8fb6 205#endif // wxUSE_PALETTE
1971d23c
VZ
206 }
207
208 int i;
209 unsigned char r, g, b;
210 rgbquad = new wxUint8 [palette_size*4];
211
212 for (i=0; i<palette_size; i++)
213 {
b11e8fb6
VZ
214#if wxUSE_PALETTE
215 if (!palette->GetRGB( i, &r, &g, &b ))
216#endif // wxUSE_PALETTE
217 r = g = b = 0;
1971d23c
VZ
218
219 rgbquad[i*4] = b;
220 rgbquad[i*4+1] = g;
221 rgbquad[i*4+2] = r;
222 rgbquad[i*4+3] = 0;
223 }
224 }
225 // make a 256 entry greyscale colormap or 2 entry black & white
226 else if ((format == wxBMP_8BPP_GREY) || (format == wxBMP_8BPP_RED) ||
227 (format == wxBMP_1BPP_BW))
228 {
229 int i;
230 rgbquad = new wxUint8 [palette_size*4];
231
232 for (i=0; i<palette_size; i++)
233 {
234 // if 1BPP_BW then just 0 and 255 then exit
235 if (( i > 0) && (format == wxBMP_1BPP_BW)) i = 255;
236 rgbquad[i*4] = i;
237 rgbquad[i*4+1] = i;
238 rgbquad[i*4+2] = i;
239 rgbquad[i*4+3] = 0;
240 }
241 }
242
243 // if the colormap was made, then it needs to be written
244 if (rgbquad)
245 {
246 if (!stream.Write(rgbquad, palette_size*4))
247 {
b11e8fb6
VZ
248 if (verbose)
249 wxLogError(_("BMP: Couldn't write RGB color map."));
250 delete [] rgbquad;
251#if wxUSE_PALETTE
252 delete palette;
253#endif // wxUSE_PALETTE
254 delete q_image;
1971d23c
VZ
255 return FALSE;
256 }
257 delete []rgbquad;
258 }
259
260 // pointer to the image data, use quantized if available
f6bcfd97 261 wxUint8 *data = (wxUint8*) image->GetData();
1971d23c
VZ
262 if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData();
263
f6bcfd97 264 wxUint8 *buffer = new wxUint8[row_width];
f6bcfd97
BP
265 memset(buffer, 0, row_width);
266 int y; unsigned x;
1971d23c 267 long int pixel;
f6bcfd97
BP
268
269 for (y = image->GetHeight() -1 ; y >= 0; y--)
270 {
1971d23c
VZ
271 if (format == wxBMP_24BPP) // 3 bytes per pixel red,green,blue
272 {
273 for (x = 0; x < width; x++)
274 {
275 pixel = 3*(y*width + x);
276
277 buffer[3*x ] = data[pixel+2];
278 buffer[3*x + 1] = data[pixel+1];
279 buffer[3*x + 2] = data[pixel];
280 }
281 }
282 else if ((format == wxBMP_8BPP) || // 1 byte per pixel in color
283 (format == wxBMP_8BPP_PALETTE))
284 {
285 for (x = 0; x < width; x++)
286 {
287 pixel = 3*(y*width + x);
b11e8fb6 288#if wxUSE_PALETTE
1971d23c
VZ
289 buffer[x] = palette->GetPixel( data[pixel],
290 data[pixel+1],
291 data[pixel+2] );
b11e8fb6
VZ
292#else
293 // FIXME: what should this be? use some std palette maybe?
294 buffer[x] = 0;
295#endif // wxUSE_PALETTE
1971d23c
VZ
296 }
297 }
298 else if (format == wxBMP_8BPP_GREY) // 1 byte per pix, rgb ave to grey
299 {
300 for (x = 0; x < width; x++)
301 {
302 pixel = 3*(y*width + x);
303 buffer[x] = (wxUint8)(.299*data[pixel] +
304 .587*data[pixel+1] +
305 .114*data[pixel+2]);
306 }
307 }
308 else if (format == wxBMP_8BPP_RED) // 1 byte per pixel, red as greys
f6bcfd97 309 {
1971d23c
VZ
310 for (x = 0; x < width; x++)
311 {
312 buffer[x] = (wxUint8)data[3*(y*width + x)];
313 }
314 }
315 else if (format == wxBMP_4BPP) // 4 bpp in color
316 {
317 for (x = 0; x < width; x+=2)
318 {
319 pixel = 3*(y*width + x);
320
321 // fill buffer, ignore if > width
b11e8fb6 322#if wxUSE_PALETTE
1971d23c 323 buffer[x/2] =
b11e8fb6
VZ
324 ((wxUint8)palette->GetPixel(data[pixel],
325 data[pixel+1],
326 data[pixel+2]) << 4) |
327 (((x+1) > width)
328 ? 0
329 : ((wxUint8)palette->GetPixel(data[pixel+3],
330 data[pixel+4],
331 data[pixel+5]) ));
332#else
333 // FIXME: what should this be? use some std palette maybe?
334 buffer[x/2] = 0;
335#endif // wxUSE_PALETTE
1971d23c
VZ
336 }
337 }
338 else if (format == wxBMP_1BPP) // 1 bpp in "color"
339 {
340 for (x = 0; x < width; x+=8)
341 {
342 pixel = 3*(y*width + x);
343
b11e8fb6
VZ
344#if wxUSE_PALETTE
345 buffer[x/8] = ((wxUint8)palette->GetPixel(data[pixel], data[pixel+1], data[pixel+2]) << 7) |
1971d23c
VZ
346 (((x+1) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+3], data[pixel+4], data[pixel+5]) << 6)) |
347 (((x+2) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+6], data[pixel+7], data[pixel+8]) << 5)) |
348 (((x+3) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+9], data[pixel+10], data[pixel+11]) << 4)) |
349 (((x+4) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+12], data[pixel+13], data[pixel+14]) << 3)) |
350 (((x+5) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+15], data[pixel+16], data[pixel+17]) << 2)) |
351 (((x+6) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+18], data[pixel+19], data[pixel+20]) << 1)) |
352 (((x+7) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+21], data[pixel+22], data[pixel+23]) ));
b11e8fb6
VZ
353#else
354 // FIXME: what should this be? use some std palette maybe?
355 buffer[x/8] = 0;
356#endif // wxUSE_PALETTE
1971d23c
VZ
357 }
358 }
359 else if (format == wxBMP_1BPP_BW) // 1 bpp B&W colormap from red color ONLY
360 {
361 for (x = 0; x < width; x+=8)
362 {
363 pixel = 3*(y*width + x);
364
365 buffer[x/8] =
366 (((wxUint8)(data[pixel] /128.)) << 7) |
367 ( ((x+1) > width) ? 0 : (((wxUint8)(data[pixel+3] /128.)) << 6)) |
368 ( ((x+2) > width) ? 0 : (((wxUint8)(data[pixel+6] /128.)) << 5)) |
369 ( ((x+3) > width) ? 0 : (((wxUint8)(data[pixel+9] /128.)) << 4)) |
370 ( ((x+4) > width) ? 0 : (((wxUint8)(data[pixel+12]/128.)) << 3)) |
371 ( ((x+5) > width) ? 0 : (((wxUint8)(data[pixel+15]/128.)) << 2)) |
372 ( ((x+6) > width) ? 0 : (((wxUint8)(data[pixel+18]/128.)) << 1)) |
373 ( ((x+7) > width) ? 0 : (((wxUint8)(data[pixel+21]/128.)) ));
374 }
f6bcfd97 375 }
33ac7e6f 376
f6bcfd97
BP
377 if (!stream.Write(buffer, row_width))
378 {
379 if (verbose)
380 wxLogError(_("BMP: Couldn't write data."));
381 delete[] buffer;
b11e8fb6
VZ
382#if wxUSE_PALETTE
383 delete palette;
384#endif // wxUSE_PALETTE
385 delete q_image;
f6bcfd97
BP
386 return FALSE;
387 }
388 }
389 delete[] buffer;
b11e8fb6
VZ
390#if wxUSE_PALETTE
391 delete palette;
392#endif // wxUSE_PALETTE
393 delete q_image;
f6bcfd97
BP
394
395 return TRUE;
396}
397
398
399
e65ed37a
RR
400#ifndef BI_RGB
401#define BI_RGB 0
402#define BI_RLE8 1
403#define BI_RLE4 2
404#endif
405
406#ifndef BI_BITFIELDS
407#define BI_BITFIELDS 3
408#endif
409
410#define poffset (line * width * 3 + column * 3)
411
58c837a4 412bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
e65ed37a
RR
413{
414 int rshift = 0, gshift = 0, bshift = 0;
415 wxUint8 aByte;
416 wxUint16 aWord;
33ac7e6f
KB
417 wxInt32 dbuf[4];
418 wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0;
e65ed37a
RR
419 wxInt8 bbuf[4];
420 struct _cmap {
421 unsigned char r, g, b;
422 } *cmap = NULL;
31528cd3 423
e65ed37a 424 off_t start_offset = stream.TellI();
f6bcfd97 425 if (start_offset == wxInvalidOffset) start_offset = 0;
e65ed37a
RR
426
427 image->Destroy();
428
429 /*
430 * Read the BMP header
431 */
432
33ac7e6f 433 stream.Read( bbuf, 2 );
e65ed37a
RR
434 stream.Read( dbuf, 4 * 4 );
435
31528cd3 436#if 0 // unused
e65ed37a 437 wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
31528cd3 438#endif
e65ed37a
RR
439 wxInt32 offset = wxINT32_SWAP_ON_BE( dbuf[2] );
440
441 stream.Read(dbuf, 4 * 2);
442 int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
443 int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
444 if (width > 32767)
445 {
58c837a4
RR
446 if (verbose)
447 wxLogError( _("BMP: Image width > 32767 pixels for file.") );
e65ed37a
RR
448 return FALSE;
449 }
450 if (height > 32767)
451 {
58c837a4
RR
452 if (verbose)
453 wxLogError( _("BMP: Image height > 32767 pixels for file.") );
e65ed37a
RR
454 return FALSE;
455 }
31528cd3 456
e65ed37a
RR
457 stream.Read( &aWord, 2 );
458/*
459 TODO
460 int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
461*/
462 stream.Read( &aWord, 2 );
463 int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
464 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
465 {
58c837a4
RR
466 if (verbose)
467 wxLogError( _("BMP: Unknown bitdepth in file.") );
e65ed37a
RR
468 return FALSE;
469 }
31528cd3 470
e65ed37a
RR
471 stream.Read( dbuf, 4 * 4 );
472 int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
473 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
474 {
58c837a4
RR
475 if (verbose)
476 wxLogError( _("BMP: Unknown encoding in file.") );
e65ed37a
RR
477 return FALSE;
478 }
31528cd3 479
e65ed37a
RR
480 stream.Read( dbuf, 4 * 2 );
481 int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
482 if (ncolors == 0)
483 ncolors = 1 << bpp;
484 /* some more sanity checks */
31528cd3
VZ
485 if (((comp == BI_RLE4) && (bpp != 4)) ||
486 ((comp == BI_RLE8) && (bpp != 8)) ||
487 ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
e65ed37a 488 {
58c837a4
RR
489 if (verbose)
490 wxLogError( _("BMP: Encoding doesn't match bitdepth.") );
e65ed37a
RR
491 return FALSE;
492 }
493 if (bpp < 16)
494 {
495 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
496 if (!cmap)
497 {
58c837a4
RR
498 if (verbose)
499 wxLogError( _("BMP: Couldn't allocate memory.") );
e65ed37a
RR
500 return FALSE;
501 }
502 }
503 else
504 cmap = NULL;
505
506 image->Create( width, height );
507 unsigned char *ptr = image->GetData();
508 if (!ptr)
509 {
58c837a4
RR
510 if (verbose)
511 wxLogError( _("BMP: Couldn't allocate memory.") );
e65ed37a
RR
512 if (cmap)
513 free(cmap);
514 return FALSE;
515 }
516
517 /*
518 * Reading the palette, if it exists.
519 */
520 if (bpp < 16 && ncolors != 0)
521 {
3f4fc796
JS
522 unsigned char* r = new unsigned char[ncolors];
523 unsigned char* g = new unsigned char[ncolors];
524 unsigned char* b = new unsigned char[ncolors];
e65ed37a
RR
525 for (int j = 0; j < ncolors; j++)
526 {
527 stream.Read( bbuf, 4 );
528 cmap[j].b = bbuf[0];
529 cmap[j].g = bbuf[1];
530 cmap[j].r = bbuf[2];
3f4fc796
JS
531
532 r[j] = cmap[j].r;
533 g[j] = cmap[j].g;
534 b[j] = cmap[j].b;
e65ed37a 535 }
b11e8fb6
VZ
536
537#if wxUSE_PALETTE
3f4fc796
JS
538 // Set the palette for the wxImage
539 image->SetPalette(wxPalette(ncolors, r, g, b));
b11e8fb6 540#endif // wxUSE_PALETTE
3f4fc796
JS
541
542 delete[] r;
543 delete[] g;
544 delete[] b;
e65ed37a
RR
545 }
546 else if (bpp == 16 || bpp == 32)
547 {
548 if (comp == BI_BITFIELDS)
549 {
550 int bit = 0;
551 stream.Read( dbuf, 4 * 3 );
552 bmask = wxINT32_SWAP_ON_BE( dbuf[0] );
553 gmask = wxINT32_SWAP_ON_BE( dbuf[1] );
554 rmask = wxINT32_SWAP_ON_BE( dbuf[2] );
555 /* find shift amount.. ugly, but i can't think of a better way */
556 for (bit = 0; bit < bpp; bit++)
557 {
558 if (bmask & (1 << bit))
559 bshift = bit;
560 if (gmask & (1 << bit))
561 gshift = bit;
562 if (rmask & (1 << bit))
563 rshift = bit;
564 }
565 }
566 else if (bpp == 16)
567 {
568 rmask = 0x7C00;
569 gmask = 0x03E0;
570 bmask = 0x001F;
571 rshift = 10;
572 gshift = 5;
573 bshift = 0;
574 }
575 else if (bpp == 32)
576 {
577 rmask = 0x00FF0000;
578 gmask = 0x0000FF00;
579 bmask = 0x000000FF;
580 rshift = 16;
581 gshift = 8;
582 bshift = 0;
583 }
584 }
585
586 /*
587 * Reading the image data
588 */
589 stream.SeekI( start_offset + offset );
590 unsigned char *data = ptr;
591
592 /* set the whole image to the background color */
593 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
594 {
595 for (int i = 0; i < width * height; i++)
596 {
597 *ptr++ = cmap[0].r;
598 *ptr++ = cmap[0].g;
599 *ptr++ = cmap[0].b;
600 }
601 ptr = data;
602 }
31528cd3 603
e65ed37a
RR
604 int line = 0;
605 int column = 0;
606 int linesize = ((width * bpp + 31) / 32) * 4;
607
608 /* BMPs are stored upside down */
31528cd3 609 for (line = (height - 1); line >= 0; line--)
e65ed37a
RR
610 {
611 int linepos = 0;
612 for (column = 0; column < width;)
613 {
614 if (bpp < 16)
615 {
616 int index = 0;
617 linepos++;
618 aByte = stream.GetC();
619 if (bpp == 1)
620 {
621 int bit = 0;
942bef71 622 for (bit = 0; bit < 8 && column < width; bit++)
e65ed37a
RR
623 {
624 index = ((aByte & (0x80 >> bit)) ? 1 : 0);
625 ptr[poffset] = cmap[index].r;
626 ptr[poffset + 1] = cmap[index].g;
627 ptr[poffset + 2] = cmap[index].b;
628 column++;
629 }
630 }
631 else if (bpp == 4)
632 {
633 if (comp == BI_RLE4)
634 {
58c837a4
RR
635 if (verbose)
636 wxLogError( _("BMP: Cannot deal with 4bit encoded yet.") );
e65ed37a
RR
637 image->Destroy();
638 free(cmap);
639 return FALSE;
640 }
641 else
642 {
643 int nibble = 0;
942bef71 644 for (nibble = 0; nibble < 2 && column < width; nibble++)
e65ed37a
RR
645 {
646 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
647 if (index >= 16)
648 index = 15;
649 ptr[poffset] = cmap[index].r;
650 ptr[poffset + 1] = cmap[index].g;
651 ptr[poffset + 2] = cmap[index].b;
652 column++;
653 }
654 }
655 }
656 else if (bpp == 8)
657 {
658 if (comp == BI_RLE8)
659 {
660 unsigned char first;
661 first = aByte;
662 aByte = stream.GetC();
663 if (first == 0)
664 {
665 if (aByte == 0)
666 {
667 /* column = width; */
668 }
669 else if (aByte == 1)
670 {
671 column = width;
672 line = -1;
673 }
674 else if (aByte == 2)
675 {
676 aByte = stream.GetC();
677 column += aByte;
678 linepos = column * bpp / 8;
679 aByte = stream.GetC();
680 line += aByte;
681 }
682 else
683 {
684 int absolute = aByte;
685 for (int k = 0; k < absolute; k++)
686 {
687 linepos++;
688 aByte = stream.GetC();
689 ptr[poffset ] = cmap[aByte].r;
690 ptr[poffset + 1] = cmap[aByte].g;
691 ptr[poffset + 2] = cmap[aByte].b;
692 column++;
693 }
694 if (absolute & 0x01)
695 aByte = stream.GetC();
696 }
697 }
698 else
699 {
942bef71 700 for (int l = 0; l < first && column < width; l++)
e65ed37a
RR
701 {
702 ptr[poffset ] = cmap[aByte].r;
703 ptr[poffset + 1] = cmap[aByte].g;
704 ptr[poffset + 2] = cmap[aByte].b;
705 column++;
706 linepos++;
707 }
708 }
709 }
710 else
711 {
712 ptr[poffset ] = cmap[aByte].r;
713 ptr[poffset + 1] = cmap[aByte].g;
714 ptr[poffset + 2] = cmap[aByte].b;
715 column++;
953704c1 716 // linepos += size; seems to be wrong, RR
e65ed37a
RR
717 }
718 }
719 }
720 else if (bpp == 24)
721 {
33ac7e6f 722 stream.Read( bbuf, 3 );
e65ed37a
RR
723 linepos += 3;
724 ptr[poffset ] = (unsigned char)bbuf[2];
725 ptr[poffset + 1] = (unsigned char)bbuf[1];
726 ptr[poffset + 2] = (unsigned char)bbuf[0];
727 column++;
728 }
729 else if (bpp == 16)
730 {
731 unsigned char temp;
732 stream.Read( &aWord, 2 );
31528cd3 733 aWord = wxUINT16_SWAP_ON_BE( aWord );
e65ed37a
RR
734 linepos += 2;
735 temp = (aWord & rmask) >> rshift;
736 ptr[poffset] = temp;
737 temp = (aWord & gmask) >> gshift;
738 ptr[poffset + 1] = temp;
e115e771 739 temp = (aWord & bmask) >> bshift;
e65ed37a
RR
740 ptr[poffset + 2] = temp;
741 column++;
742 }
743 else
744 {
745 unsigned char temp;
746 stream.Read( &aDword, 4 );
31528cd3 747 aDword = wxINT32_SWAP_ON_BE( aDword );
e65ed37a
RR
748 linepos += 4;
749 temp = (aDword & rmask) >> rshift;
750 ptr[poffset] = temp;
751 temp = (aDword & gmask) >> gshift;
752 ptr[poffset + 1] = temp;
753 temp = (aDword & bmask) >> bshift;
754 ptr[poffset + 2] = temp;
755 column++;
756 }
757 }
758 while ((linepos < linesize) && (comp != 1) && (comp != 2))
759 {
760 stream.Read( &aByte, 1 );
761 linepos += 1;
762 if (stream.LastError() != wxStream_NOERROR)
763 break;
764 }
765 }
31528cd3 766 if (cmap)
e65ed37a
RR
767 free(cmap);
768
769 image->SetMask( FALSE );
770
771 return TRUE;
772}
773
995612e2 774bool wxBMPHandler::DoCanRead( wxInputStream& stream )
0828c087
VS
775{
776 unsigned char hdr[2];
995612e2 777
33ac7e6f 778 stream.Read(hdr, 2);
0828c087
VS
779 stream.SeekI(-2, wxFromCurrent);
780 return (hdr[0] == 'B' && hdr[1] == 'M');
781}
782
e65ed37a
RR
783#endif // wxUSE_STREAMS
784
c96ea657 785#endif // wxUSE_IMAGE