]> git.saurik.com Git - wxWidgets.git/blob - src/common/imagbmp.cpp
Applied Chris' patch for support for ICO loading.
[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/defs.h"
22
23 #if wxUSE_IMAGE
24
25 #include "wx/imagbmp.h"
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"
34 #include "wx/quantize.h"
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
53 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
54
55
56 #if wxUSE_STREAMS
57
58
59 bool 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
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?
94 if ((format == wxBMP_8BPP_PALETTE)
95 #if wxUSE_PALETTE
96 && !image->HasPalette()
97 #endif // wxUSE_PALETTE
98 )
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
114 unsigned width = image->GetWidth();
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
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
125
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;
137
138 wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/;
139
140 hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/);
141 hdr.filesize = wxUINT32_SWAP_ON_BE( hdr_size + palette_size*4 +
142 row_width * image->GetHeight() );
143 hdr.reserved = 0;
144 hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size + palette_size*4);
145
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
150 hdr.bpp = wxUINT16_SWAP_ON_BE(bpp);
151 hdr.compression = 0; // RGB uncompressed
152 hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight());
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
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)
175 )
176 {
177 if (verbose)
178 wxLogError(_("BMP: Couldn't write the file header."));
179 return FALSE;
180 }
181
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 {
203 #if wxUSE_PALETTE
204 palette = new wxPalette(image->GetPalette());
205 #endif // wxUSE_PALETTE
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 {
214 #if wxUSE_PALETTE
215 if (!palette->GetRGB( i, &r, &g, &b ))
216 #endif // wxUSE_PALETTE
217 r = g = b = 0;
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 {
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;
255 return FALSE;
256 }
257 delete []rgbquad;
258 }
259
260 // pointer to the image data, use quantized if available
261 wxUint8 *data = (wxUint8*) image->GetData();
262 if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData();
263
264 wxUint8 *buffer = new wxUint8[row_width];
265 memset(buffer, 0, row_width);
266 int y; unsigned x;
267 long int pixel;
268
269 for (y = image->GetHeight() -1 ; y >= 0; y--)
270 {
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);
288 #if wxUSE_PALETTE
289 buffer[x] = palette->GetPixel( data[pixel],
290 data[pixel+1],
291 data[pixel+2] );
292 #else
293 // FIXME: what should this be? use some std palette maybe?
294 buffer[x] = 0;
295 #endif // wxUSE_PALETTE
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
309 {
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
322 #if wxUSE_PALETTE
323 buffer[x/2] =
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
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
344 #if wxUSE_PALETTE
345 buffer[x/8] = ((wxUint8)palette->GetPixel(data[pixel], data[pixel+1], data[pixel+2]) << 7) |
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]) ));
353 #else
354 // FIXME: what should this be? use some std palette maybe?
355 buffer[x/8] = 0;
356 #endif // wxUSE_PALETTE
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 }
375 }
376
377 if (!stream.Write(buffer, row_width))
378 {
379 if (verbose)
380 wxLogError(_("BMP: Couldn't write data."));
381 delete[] buffer;
382 #if wxUSE_PALETTE
383 delete palette;
384 #endif // wxUSE_PALETTE
385 delete q_image;
386 return FALSE;
387 }
388 }
389 delete[] buffer;
390 #if wxUSE_PALETTE
391 delete palette;
392 #endif // wxUSE_PALETTE
393 delete q_image;
394
395 return TRUE;
396 }
397
398
399
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
412
413
414 struct 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
427 struct ICONDIR
428 {
429 wxUint16 idReserved; // Reserved
430 wxUint16 idType; // resource type (1 for icons)
431 wxUint16 idCount; // how many images?
432 } ;
433
434
435 bool 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 )
438 {
439
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;
446
447
448 // allocate space for palette if needed
449 struct _cmap
450 {
451 unsigned char r, g, b;
452 }
453 *cmap = NULL;
454
455 if (bpp < 16)
456 {
457 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
458 if (!cmap)
459 {
460 if (verbose)
461 wxLogError( _("Loading DIB : Couldn't allocate memory.") );
462 return FALSE;
463 }
464 }
465 else
466 cmap = NULL;
467
468 // destroy existing here instead of
469 image->Destroy();
470 image->Create( width, height );
471 unsigned char *ptr = image->GetData();
472 if (!ptr)
473 {
474 if (verbose)
475 wxLogError( _("Loading DIB : Couldn't allocate memory.") );
476 if (cmap)
477 free(cmap);
478 return FALSE;
479 }
480 /*
481 * Reading the palette, if it exists.
482 */
483 if (bpp < 16 && ncolors != 0)
484 {
485 unsigned char* r = new unsigned char[ncolors];
486 unsigned char* g = new unsigned char[ncolors];
487 unsigned char* b = new unsigned char[ncolors];
488 for (int j = 0; j < ncolors; j++)
489 {
490 if (hasPalette)
491 {
492 stream.Read( bbuf, 4 );
493 cmap[j].b = bbuf[0];
494 cmap[j].g = bbuf[1];
495 cmap[j].r = bbuf[2];
496
497 r[j] = cmap[j].r;
498 g[j] = cmap[j].g;
499 b[j] = cmap[j].b;
500 }
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 }
509
510 #if wxUSE_PALETTE
511 // Set the palette for the wxImage
512 image->SetPalette(wxPalette(ncolors, r, g, b));
513 #endif // wxUSE_PALETTE
514
515 delete[] r;
516 delete[] g;
517 delete[] b;
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 */
562 if ( IsBmp ) stream.SeekI( bmpOffset ); // else icon, just carry on
563
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 }
577
578 int line = 0;
579 int column = 0;
580 int linesize = ((width * bpp + 31) / 32) * 4;
581
582 /* BMPs are stored upside down */
583 for (line = (height - 1); line >= 0; line--)
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;
596 for (bit = 0; bit < 8 && column < width; bit++)
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 {
609 if (verbose)
610 wxLogError( _("DIB Header: Cannot deal with 4bit encoded yet.") );
611 image->Destroy();
612 free(cmap);
613 return FALSE;
614 }
615 else
616 {
617 int nibble = 0;
618 for (nibble = 0; nibble < 2 && column < width; nibble++)
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 {
674 for (int l = 0; l < first && column < width; l++)
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++;
690 // linepos += size; seems to be wrong, RR
691 }
692 }
693 }
694 else if (bpp == 24)
695 {
696 stream.Read( bbuf, 3 );
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 );
707 aWord = wxUINT16_SWAP_ON_BE( aWord );
708 linepos += 2;
709 temp = (aWord & rmask) >> rshift;
710 ptr[poffset] = temp;
711 temp = (aWord & gmask) >> gshift;
712 ptr[poffset + 1] = temp;
713 temp = (aWord & bmask) >> bshift;
714 ptr[poffset + 2] = temp;
715 column++;
716 }
717 else
718 {
719 unsigned char temp;
720 stream.Read( &aDword, 4 );
721 aDword = wxINT32_SWAP_ON_BE( aDword );
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 }
740 if (cmap)
741 free(cmap);
742
743 image->SetMask( FALSE );
744
745 return stream.IsOk();
746 }
747
748
749 bool wxBMPHandler::LoadDib( wxImage *image, wxInputStream& stream, bool verbose, bool IsBmp )
750 {
751
752 wxUint8 aByte;
753 wxUint16 aWord;
754 wxInt32 dbuf[4];
755 wxInt8 bbuf[4];
756 off_t offset;
757
758 offset = 0; // keep gcc quiet
759 if ( IsBmp )
760 {
761 // read the header off the .BMP format file
762
763 offset = stream.TellI();
764 if (offset == wxInvalidOffset) offset = 0;
765
766 stream.Read( bbuf, 2 );
767
768 stream.Read( dbuf, 16 );
769 }
770 else
771 {
772 stream.Read( dbuf, 4 );
773 }
774 #if 0 // unused
775 wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
776 #endif
777 offset = offset + wxINT32_SWAP_ON_BE( dbuf[2] );
778
779 stream.Read(dbuf, 4 * 2);
780 int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
781 int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
782 if ( !IsBmp ) height = height / 2; // for icons divide by 2
783
784 if (width > 32767)
785 {
786 if (verbose)
787 wxLogError( _("DIB Header: Image width > 32767 pixels for file.") );
788 return FALSE;
789 }
790 if (height > 32767)
791 {
792 if (verbose)
793 wxLogError( _("DIB Header: Image height > 32767 pixels for file.") );
794 return FALSE;
795 }
796
797 stream.Read( &aWord, 2 );
798 /*
799 TODO
800 int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
801 */
802 stream.Read( &aWord, 2 );
803 int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
804 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
805 {
806 if (verbose)
807 wxLogError( _("DIB Header: Unknown bitdepth in file.") );
808 return FALSE;
809 }
810
811 stream.Read( dbuf, 4 * 4 );
812 int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
813 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
814 {
815 if (verbose)
816 wxLogError( _("DIB Header: Unknown encoding in file.") );
817 return FALSE;
818 }
819
820 stream.Read( dbuf, 4 * 2 );
821 int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
822 if (ncolors == 0)
823 ncolors = 1 << bpp;
824 /* some more sanity checks */
825 if (((comp == BI_RLE4) && (bpp != 4)) ||
826 ((comp == BI_RLE8) && (bpp != 8)) ||
827 ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
828 {
829 if (verbose)
830 wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") );
831 return FALSE;
832 }
833
834 //read DIB; this is the BMP image or the XOR part of an icon image
835 if (!DoLoadDib (image, width, height, bpp, ncolors, comp, offset, stream,
836 verbose, IsBmp, TRUE ) )
837 {
838 if (verbose)
839 wxLogError( _("Error in reading image DIB .") );
840 return FALSE;
841 }
842
843 if ( !IsBmp )
844 {
845 //read Icon mask which is monochrome
846 //there is no palette, so we will create one
847 wxImage mask ;
848 if (!DoLoadDib (&mask, width, height, 1, 2, BI_RGB, offset, stream,
849 verbose, IsBmp, FALSE ) )
850 {
851 if (verbose)
852 wxLogError( _("ICO: Error in reading mask DIB.") );
853 return FALSE;
854 }
855 image -> ApplyMask ( &mask );
856
857 }
858 return TRUE;
859 }
860
861
862 bool wxBMPHandler::LoadFile ( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
863 {
864 bool IsBmp = TRUE;
865 //Read a single DIB fom the file
866 return LoadDib ( image, stream, verbose, IsBmp ) ;
867 }
868
869
870
871 bool wxICOHandler::LoadFile ( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
872 {
873 bool bResult = FALSE ;
874 bool IsBmp = FALSE;
875
876 ICONDIR m_IconDir ;
877 stream.Read (&m_IconDir, sizeof(m_IconDir));
878 wxUint16 nIcons = wxUINT16_SWAP_ON_BE ( m_IconDir.idCount ) ;
879
880 //loop round the icons and choose the best one
881 ICONDIRENTRY * pIconDirEntry = new ICONDIRENTRY [nIcons];
882 ICONDIRENTRY * pCurrentEntry = pIconDirEntry ;
883 int i ;
884 int wMax = 0 ;
885 int colmax = 0 ;
886 int iSel = wxNOT_FOUND ;
887 for (i=0; i < nIcons ; i++ )
888 {
889 stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY));
890 //bHeight and bColorCount are wxUint8
891 if (pCurrentEntry->bWidth >= wMax )
892 {
893 // see if we have more colors, ==0 indicates > 8bpp
894 if (pCurrentEntry->bColorCount == 0 ) pCurrentEntry->bColorCount = 255 ;
895 if (pCurrentEntry->bColorCount >= colmax)
896 {
897 iSel = i ;
898 wMax = pCurrentEntry->bWidth ;
899 colmax = pCurrentEntry->bColorCount ;
900 }
901 }
902 pCurrentEntry ++ ;
903 }
904 if (iSel == wxNOT_FOUND)
905 {
906 bResult = FALSE;
907 }
908 else
909 {
910 //seek to selected icon
911 pCurrentEntry = pIconDirEntry + iSel ;
912 stream.SeekI (wxUINT32_SWAP_ON_BE ( pCurrentEntry -> dwImageOffset ), wxFromStart ) ;
913 bResult = LoadDib ( image, stream, TRUE, IsBmp );
914 }
915 delete [] pIconDirEntry ;
916 return bResult
917 ;
918 }
919
920 bool wxICOHandler::SaveFile(wxImage *image,
921 wxOutputStream& stream,
922 bool verbose)
923 {
924 return FALSE ;
925 }
926
927 bool wxBMPHandler::DoCanRead( wxInputStream& stream )
928 {
929 unsigned char hdr[2];
930
931 stream.Read(hdr, 2);
932 stream.SeekI(-2, wxFromCurrent);
933 return (hdr[0] == 'B' && hdr[1] == 'M');
934 }
935
936 bool wxICOHandler::DoCanRead( wxInputStream& stream )
937 {
938 unsigned char hdr[4];
939
940 stream.Read(hdr, 4);
941 stream.SeekI(-4, wxFromCurrent);
942 return (hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0');
943 }
944
945 #endif // wxUSE_STREAMS
946
947 #endif // wxUSE_IMAGE