]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagbmp.cpp
blind fix for wxGIFDecoder::ReadGIF
[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
e65ed37a 412
e65ed37a 413
52b64b0a
RR
414struct ICONDIRENTRY
415 {
416 wxUint8 bWidth; // Width of the image
417 wxUint8 bHeight; // Height of the image (times 2)
418 wxUint8 bColorCount; // Number of colors in image (0 if >=8bpp)
419 wxUint8 bReserved; // Reserved
420 wxUint16 wPlanes; // Color Planes
421 wxUint16 wBitCount; // Bits per pixel
422 wxUint32 dwBytesInRes; // how many bytes in this resource?
423 wxUint32 dwImageOffset; // where in the file is this image
424} ;
425
426
427struct ICONDIR
428{
429 wxUint16 idReserved; // Reserved
430 wxUint16 idType; // resource type (1 for icons)
431 wxUint16 idCount; // how many images?
432} ;
e65ed37a 433
e65ed37a 434
52b64b0a
RR
435bool wxBMPHandler::DoLoadDib (wxImage * image, int width, int height, int bpp, int ncolors, int comp,
436 off_t bmpOffset, wxInputStream& stream,
437 bool verbose, bool IsBmp, bool hasPalette )
e65ed37a 438 {
31528cd3 439
52b64b0a
RR
440 wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0;
441 int rshift = 0, gshift = 0, bshift = 0;
442 wxInt32 dbuf[4];
443 wxInt8 bbuf[4];
444 wxUint8 aByte;
445 wxUint16 aWord;
31528cd3 446
31528cd3 447
52b64b0a
RR
448 // allocate space for palette if needed
449 struct _cmap
e65ed37a 450 {
52b64b0a 451 unsigned char r, g, b;
e65ed37a 452 }
52b64b0a
RR
453 *cmap = NULL;
454
e65ed37a
RR
455 if (bpp < 16)
456 {
457 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
458 if (!cmap)
459 {
58c837a4 460 if (verbose)
52b64b0a 461 wxLogError( _("Loading DIB : Couldn't allocate memory.") );
e65ed37a
RR
462 return FALSE;
463 }
464 }
465 else
466 cmap = NULL;
467
52b64b0a
RR
468 // destroy existing here instead of
469 image->Destroy();
e65ed37a
RR
470 image->Create( width, height );
471 unsigned char *ptr = image->GetData();
472 if (!ptr)
473 {
58c837a4 474 if (verbose)
52b64b0a 475 wxLogError( _("Loading DIB : Couldn't allocate memory.") );
e65ed37a
RR
476 if (cmap)
477 free(cmap);
478 return FALSE;
479 }
e65ed37a
RR
480 /*
481 * Reading the palette, if it exists.
482 */
483 if (bpp < 16 && ncolors != 0)
484 {
3f4fc796
JS
485 unsigned char* r = new unsigned char[ncolors];
486 unsigned char* g = new unsigned char[ncolors];
487 unsigned char* b = new unsigned char[ncolors];
e65ed37a
RR
488 for (int j = 0; j < ncolors; j++)
489 {
52b64b0a
RR
490 if (hasPalette)
491 {
e65ed37a
RR
492 stream.Read( bbuf, 4 );
493 cmap[j].b = bbuf[0];
494 cmap[j].g = bbuf[1];
495 cmap[j].r = bbuf[2];
3f4fc796
JS
496
497 r[j] = cmap[j].r;
498 g[j] = cmap[j].g;
499 b[j] = cmap[j].b;
e65ed37a 500 }
52b64b0a
RR
501 else
502 {
503 //used in reading .ico file mask
504 r[j] = cmap[j].r = j * 255;
505 g[j] = cmap[j].g = j * 255;
506 b[j] = cmap[j].b = j * 255;
507 }
508 }
b11e8fb6
VZ
509
510#if wxUSE_PALETTE
3f4fc796
JS
511 // Set the palette for the wxImage
512 image->SetPalette(wxPalette(ncolors, r, g, b));
b11e8fb6 513#endif // wxUSE_PALETTE
3f4fc796
JS
514
515 delete[] r;
516 delete[] g;
517 delete[] b;
e65ed37a
RR
518 }
519 else if (bpp == 16 || bpp == 32)
520 {
521 if (comp == BI_BITFIELDS)
522 {
523 int bit = 0;
524 stream.Read( dbuf, 4 * 3 );
525 bmask = wxINT32_SWAP_ON_BE( dbuf[0] );
526 gmask = wxINT32_SWAP_ON_BE( dbuf[1] );
527 rmask = wxINT32_SWAP_ON_BE( dbuf[2] );
528 /* find shift amount.. ugly, but i can't think of a better way */
529 for (bit = 0; bit < bpp; bit++)
530 {
531 if (bmask & (1 << bit))
532 bshift = bit;
533 if (gmask & (1 << bit))
534 gshift = bit;
535 if (rmask & (1 << bit))
536 rshift = bit;
537 }
538 }
539 else if (bpp == 16)
540 {
541 rmask = 0x7C00;
542 gmask = 0x03E0;
543 bmask = 0x001F;
544 rshift = 10;
545 gshift = 5;
546 bshift = 0;
547 }
548 else if (bpp == 32)
549 {
550 rmask = 0x00FF0000;
551 gmask = 0x0000FF00;
552 bmask = 0x000000FF;
553 rshift = 16;
554 gshift = 8;
555 bshift = 0;
556 }
557 }
558
559 /*
560 * Reading the image data
561 */
52b64b0a
RR
562 if ( IsBmp ) stream.SeekI( bmpOffset ); // else icon, just carry on
563
e65ed37a
RR
564 unsigned char *data = ptr;
565
566 /* set the whole image to the background color */
567 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
568 {
569 for (int i = 0; i < width * height; i++)
570 {
571 *ptr++ = cmap[0].r;
572 *ptr++ = cmap[0].g;
573 *ptr++ = cmap[0].b;
574 }
575 ptr = data;
576 }
31528cd3 577
e65ed37a
RR
578 int line = 0;
579 int column = 0;
580 int linesize = ((width * bpp + 31) / 32) * 4;
581
582 /* BMPs are stored upside down */
31528cd3 583 for (line = (height - 1); line >= 0; line--)
e65ed37a
RR
584 {
585 int linepos = 0;
586 for (column = 0; column < width;)
587 {
588 if (bpp < 16)
589 {
590 int index = 0;
591 linepos++;
592 aByte = stream.GetC();
593 if (bpp == 1)
594 {
595 int bit = 0;
942bef71 596 for (bit = 0; bit < 8 && column < width; bit++)
e65ed37a
RR
597 {
598 index = ((aByte & (0x80 >> bit)) ? 1 : 0);
599 ptr[poffset] = cmap[index].r;
600 ptr[poffset + 1] = cmap[index].g;
601 ptr[poffset + 2] = cmap[index].b;
602 column++;
603 }
604 }
605 else if (bpp == 4)
606 {
607 if (comp == BI_RLE4)
608 {
58c837a4 609 if (verbose)
52b64b0a 610 wxLogError( _("DIB Header: Cannot deal with 4bit encoded yet.") );
e65ed37a
RR
611 image->Destroy();
612 free(cmap);
613 return FALSE;
614 }
615 else
616 {
617 int nibble = 0;
942bef71 618 for (nibble = 0; nibble < 2 && column < width; nibble++)
e65ed37a
RR
619 {
620 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
621 if (index >= 16)
622 index = 15;
623 ptr[poffset] = cmap[index].r;
624 ptr[poffset + 1] = cmap[index].g;
625 ptr[poffset + 2] = cmap[index].b;
626 column++;
627 }
628 }
629 }
630 else if (bpp == 8)
631 {
632 if (comp == BI_RLE8)
633 {
634 unsigned char first;
635 first = aByte;
636 aByte = stream.GetC();
637 if (first == 0)
638 {
639 if (aByte == 0)
640 {
641 /* column = width; */
642 }
643 else if (aByte == 1)
644 {
645 column = width;
646 line = -1;
647 }
648 else if (aByte == 2)
649 {
650 aByte = stream.GetC();
651 column += aByte;
652 linepos = column * bpp / 8;
653 aByte = stream.GetC();
654 line += aByte;
655 }
656 else
657 {
658 int absolute = aByte;
659 for (int k = 0; k < absolute; k++)
660 {
661 linepos++;
662 aByte = stream.GetC();
663 ptr[poffset ] = cmap[aByte].r;
664 ptr[poffset + 1] = cmap[aByte].g;
665 ptr[poffset + 2] = cmap[aByte].b;
666 column++;
667 }
668 if (absolute & 0x01)
669 aByte = stream.GetC();
670 }
671 }
672 else
673 {
942bef71 674 for (int l = 0; l < first && column < width; l++)
e65ed37a
RR
675 {
676 ptr[poffset ] = cmap[aByte].r;
677 ptr[poffset + 1] = cmap[aByte].g;
678 ptr[poffset + 2] = cmap[aByte].b;
679 column++;
680 linepos++;
681 }
682 }
683 }
684 else
685 {
686 ptr[poffset ] = cmap[aByte].r;
687 ptr[poffset + 1] = cmap[aByte].g;
688 ptr[poffset + 2] = cmap[aByte].b;
689 column++;
953704c1 690 // linepos += size; seems to be wrong, RR
e65ed37a
RR
691 }
692 }
693 }
694 else if (bpp == 24)
695 {
33ac7e6f 696 stream.Read( bbuf, 3 );
e65ed37a
RR
697 linepos += 3;
698 ptr[poffset ] = (unsigned char)bbuf[2];
699 ptr[poffset + 1] = (unsigned char)bbuf[1];
700 ptr[poffset + 2] = (unsigned char)bbuf[0];
701 column++;
702 }
703 else if (bpp == 16)
704 {
705 unsigned char temp;
706 stream.Read( &aWord, 2 );
31528cd3 707 aWord = wxUINT16_SWAP_ON_BE( aWord );
e65ed37a
RR
708 linepos += 2;
709 temp = (aWord & rmask) >> rshift;
710 ptr[poffset] = temp;
711 temp = (aWord & gmask) >> gshift;
712 ptr[poffset + 1] = temp;
e115e771 713 temp = (aWord & bmask) >> bshift;
e65ed37a
RR
714 ptr[poffset + 2] = temp;
715 column++;
716 }
717 else
718 {
719 unsigned char temp;
720 stream.Read( &aDword, 4 );
31528cd3 721 aDword = wxINT32_SWAP_ON_BE( aDword );
e65ed37a
RR
722 linepos += 4;
723 temp = (aDword & rmask) >> rshift;
724 ptr[poffset] = temp;
725 temp = (aDword & gmask) >> gshift;
726 ptr[poffset + 1] = temp;
727 temp = (aDword & bmask) >> bshift;
728 ptr[poffset + 2] = temp;
729 column++;
730 }
731 }
732 while ((linepos < linesize) && (comp != 1) && (comp != 2))
733 {
734 stream.Read( &aByte, 1 );
735 linepos += 1;
736 if (stream.LastError() != wxStream_NOERROR)
737 break;
738 }
739 }
31528cd3 740 if (cmap)
e65ed37a
RR
741 free(cmap);
742
743 image->SetMask( FALSE );
744
52b64b0a
RR
745 return stream.IsOk();
746}
747
748
749bool wxBMPHandler::LoadDib( wxImage *image, wxInputStream& stream, bool verbose, bool IsBmp )
750{
52b64b0a
RR
751 wxUint16 aWord;
752 wxInt32 dbuf[4];
753 wxInt8 bbuf[4];
754 off_t offset;
755
756 offset = 0; // keep gcc quiet
757 if ( IsBmp )
758 {
759 // read the header off the .BMP format file
760
761 offset = stream.TellI();
762 if (offset == wxInvalidOffset) offset = 0;
763
764 stream.Read( bbuf, 2 );
765
766 stream.Read( dbuf, 16 );
767 }
768 else
769 {
770 stream.Read( dbuf, 4 );
771 }
772 #if 0 // unused
773 wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
774 #endif
775 offset = offset + wxINT32_SWAP_ON_BE( dbuf[2] );
776
777 stream.Read(dbuf, 4 * 2);
778 int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
779 int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
780 if ( !IsBmp ) height = height / 2; // for icons divide by 2
781
782 if (width > 32767)
783 {
784 if (verbose)
785 wxLogError( _("DIB Header: Image width > 32767 pixels for file.") );
786 return FALSE;
787 }
788 if (height > 32767)
789 {
790 if (verbose)
791 wxLogError( _("DIB Header: Image height > 32767 pixels for file.") );
792 return FALSE;
793 }
794
795 stream.Read( &aWord, 2 );
796 /*
797 TODO
798 int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
799 */
800 stream.Read( &aWord, 2 );
801 int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
802 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
803 {
804 if (verbose)
805 wxLogError( _("DIB Header: Unknown bitdepth in file.") );
806 return FALSE;
807 }
808
809 stream.Read( dbuf, 4 * 4 );
810 int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
811 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
812 {
813 if (verbose)
814 wxLogError( _("DIB Header: Unknown encoding in file.") );
815 return FALSE;
816 }
817
818 stream.Read( dbuf, 4 * 2 );
819 int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
820 if (ncolors == 0)
821 ncolors = 1 << bpp;
822 /* some more sanity checks */
823 if (((comp == BI_RLE4) && (bpp != 4)) ||
824 ((comp == BI_RLE8) && (bpp != 8)) ||
825 ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
826 {
827 if (verbose)
828 wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") );
829 return FALSE;
830 }
831
832 //read DIB; this is the BMP image or the XOR part of an icon image
833 if (!DoLoadDib (image, width, height, bpp, ncolors, comp, offset, stream,
834 verbose, IsBmp, TRUE ) )
835 {
836 if (verbose)
837 wxLogError( _("Error in reading image DIB .") );
838 return FALSE;
839 }
840
841 if ( !IsBmp )
842 {
843 //read Icon mask which is monochrome
844 //there is no palette, so we will create one
1f5b2017 845 wxImage mask;
52b64b0a
RR
846 if (!DoLoadDib (&mask, width, height, 1, 2, BI_RGB, offset, stream,
847 verbose, IsBmp, FALSE ) )
848 {
849 if (verbose)
850 wxLogError( _("ICO: Error in reading mask DIB.") );
851 return FALSE;
852 }
1f5b2017 853 image->SetMaskFromImage(mask, 255, 255, 255);
52b64b0a
RR
854
855 }
e65ed37a
RR
856 return TRUE;
857}
858
52b64b0a
RR
859
860bool wxBMPHandler::LoadFile ( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
861{
862 bool IsBmp = TRUE;
863 //Read a single DIB fom the file
864 return LoadDib ( image, stream, verbose, IsBmp ) ;
865}
866
867
868
869bool wxICOHandler::LoadFile ( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
870{
871 bool bResult = FALSE ;
872 bool IsBmp = FALSE;
873
874 ICONDIR m_IconDir ;
875 stream.Read (&m_IconDir, sizeof(m_IconDir));
876 wxUint16 nIcons = wxUINT16_SWAP_ON_BE ( m_IconDir.idCount ) ;
877
878 //loop round the icons and choose the best one
879 ICONDIRENTRY * pIconDirEntry = new ICONDIRENTRY [nIcons];
880 ICONDIRENTRY * pCurrentEntry = pIconDirEntry ;
881 int i ;
882 int wMax = 0 ;
883 int colmax = 0 ;
884 int iSel = wxNOT_FOUND ;
885 for (i=0; i < nIcons ; i++ )
886 {
887 stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY));
888 //bHeight and bColorCount are wxUint8
889 if (pCurrentEntry->bWidth >= wMax )
890 {
891 // see if we have more colors, ==0 indicates > 8bpp
892 if (pCurrentEntry->bColorCount == 0 ) pCurrentEntry->bColorCount = 255 ;
893 if (pCurrentEntry->bColorCount >= colmax)
894 {
895 iSel = i ;
896 wMax = pCurrentEntry->bWidth ;
897 colmax = pCurrentEntry->bColorCount ;
898 }
899 }
900 pCurrentEntry ++ ;
901 }
902 if (iSel == wxNOT_FOUND)
903 {
904 bResult = FALSE;
905 }
906 else
907 {
908 //seek to selected icon
909 pCurrentEntry = pIconDirEntry + iSel ;
910 stream.SeekI (wxUINT32_SWAP_ON_BE ( pCurrentEntry -> dwImageOffset ), wxFromStart ) ;
911 bResult = LoadDib ( image, stream, TRUE, IsBmp );
912 }
913 delete [] pIconDirEntry ;
914 return bResult
915 ;
916}
917
918bool wxICOHandler::SaveFile(wxImage *image,
919 wxOutputStream& stream,
920 bool verbose)
921{
922 return FALSE ;
923}
924
995612e2 925bool wxBMPHandler::DoCanRead( wxInputStream& stream )
0828c087
VS
926{
927 unsigned char hdr[2];
995612e2 928
33ac7e6f 929 stream.Read(hdr, 2);
0828c087
VS
930 stream.SeekI(-2, wxFromCurrent);
931 return (hdr[0] == 'B' && hdr[1] == 'M');
932}
933
52b64b0a
RR
934bool wxICOHandler::DoCanRead( wxInputStream& stream )
935{
936 unsigned char hdr[4];
937
938 stream.Read(hdr, 4);
939 stream.SeekI(-4, wxFromCurrent);
940 return (hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0');
941}
942
e65ed37a
RR
943#endif // wxUSE_STREAMS
944
c96ea657 945#endif // wxUSE_IMAGE