1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/imagbmp.cpp
3 // Purpose:     wxImage BMP,ICO and CUR handlers
4 // Author:      Robert Roebling, Chris Elliott
5 // RCS-ID:      $Id: imagbmp.cpp 54942 2008-08-03 00:23:38Z VZ $
6 // Copyright:   (c) Robert Roebling, Chris Elliott
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12 
13 #ifdef __BORLANDC__
14     #pragma hdrstop
15 #endif
16 
17 #if wxUSE_IMAGE
18 
19 #include "wx/imagbmp.h"
20 
21 #ifndef WX_PRECOMP
22     #ifdef __WXMSW__
23         #include "wx/msw/wrapwin.h"
24     #endif
25     #include "wx/log.h"
26     #include "wx/app.h"
27     #include "wx/bitmap.h"
28     #include "wx/palette.h"
29     #include "wx/intl.h"
30 #endif
31 
32 #include "wx/filefn.h"
33 #include "wx/wfstream.h"
34 #include "wx/quantize.h"
35 #include "wx/anidecod.h"
36 
37 // For memcpy
38 #include <string.h>
39 
40 #ifdef __SALFORDC__
41 #ifdef FAR
42 #undef FAR
43 #endif
44 #endif
45 
46 //-----------------------------------------------------------------------------
47 // wxBMPHandler
48 //-----------------------------------------------------------------------------
49 
IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)50 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
51 
52 #if wxUSE_STREAMS
53 
54 #ifndef BI_RGB
55     #define BI_RGB       0
56 #endif
57 
58 #ifndef BI_RLE8
59 #define BI_RLE8      1
60 #endif
61 
62 #ifndef BI_RLE4
63 #define BI_RLE4      2
64 #endif
65 
66 #ifndef BI_BITFIELDS
67 #define BI_BITFIELDS 3
68 #endif
69 
70 #define poffset (line * width * 3 + column * 3)
71 
72 bool wxBMPHandler::SaveFile(wxImage *image,
73                             wxOutputStream& stream,
74                             bool verbose)
75 {
76     return SaveDib(image, stream, verbose, true/*IsBmp*/, false/*IsMask*/);
77 }
78 
SaveDib(wxImage * image,wxOutputStream & stream,bool verbose,bool IsBmp,bool IsMask)79 bool wxBMPHandler::SaveDib(wxImage *image,
80                            wxOutputStream& stream,
81                            bool verbose,
82                            bool IsBmp,
83                            bool IsMask)
84 
85 {
86     wxCHECK_MSG( image, false, _T("invalid pointer in wxBMPHandler::SaveFile") );
87 
88     if ( !image->Ok() )
89     {
90         if ( verbose )
91             wxLogError(_("BMP: Couldn't save invalid image."));
92         return false;
93     }
94 
95     // get the format of the BMP file to save, else use 24bpp
96     unsigned format = wxBMP_24BPP;
97     if ( image->HasOption(wxIMAGE_OPTION_BMP_FORMAT) )
98         format = image->GetOptionInt(wxIMAGE_OPTION_BMP_FORMAT);
99 
100     wxUint16 bpp;     // # of bits per pixel
101     int palette_size; // # of color map entries, ie. 2^bpp colors
102 
103     // set the bpp and appropriate palette_size, and do additional checks
104     if ( (format == wxBMP_1BPP) || (format == wxBMP_1BPP_BW) )
105     {
106         bpp = 1;
107         palette_size = 2;
108     }
109     else if ( format == wxBMP_4BPP )
110     {
111         bpp = 4;
112         palette_size = 16;
113     }
114     else if ( (format == wxBMP_8BPP) || (format == wxBMP_8BPP_GREY) ||
115               (format == wxBMP_8BPP_RED) || (format == wxBMP_8BPP_PALETTE) )
116     {
117         // need to set a wxPalette to use this, HOW TO CHECK IF VALID, SIZE?
118         if ((format == wxBMP_8BPP_PALETTE)
119 #if wxUSE_PALETTE
120                 && !image->HasPalette()
121 #endif // wxUSE_PALETTE
122             )
123         {
124             if ( verbose )
125                 wxLogError(_("BMP: wxImage doesn't have own wxPalette."));
126             return false;
127         }
128         bpp = 8;
129         palette_size = 256;
130     }
131     else  // you get 24bpp
132     {
133         format = wxBMP_24BPP;
134         bpp = 24;
135         palette_size = 0;
136     }
137 
138     unsigned width = image->GetWidth();
139     unsigned row_padding = (4 - int(width*bpp/8.0) % 4) % 4; // # bytes to pad to dword
140     unsigned row_width = int(width * bpp/8.0) + row_padding; // # of bytes per row
141 
142     struct
143     {
144         // BitmapHeader:
145         wxUint16  magic;          // format magic, always 'BM'
146         wxUint32  filesize;       // total file size, inc. headers
147         wxUint32  reserved;       // for future use
148         wxUint32  data_offset;    // image data offset in the file
149 
150         // BitmapInfoHeader:
151         wxUint32  bih_size;       // 2nd part's size
152         wxUint32  width, height;  // bitmap's dimensions
153         wxUint16  planes;         // num of planes
154         wxUint16  bpp;            // bits per pixel
155         wxUint32  compression;    // compression method
156         wxUint32  size_of_bmp;    // size of the bitmap
157         wxUint32  h_res, v_res;   // image resolution in dpi
158         wxUint32  num_clrs;       // number of colors used
159         wxUint32  num_signif_clrs;// number of significant colors
160     } hdr;
161 
162     wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/;
163 
164     hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/);
165     hdr.filesize = wxUINT32_SWAP_ON_BE( hdr_size + palette_size*4 +
166                                         row_width * image->GetHeight() );
167     hdr.reserved = 0;
168     hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size + palette_size*4);
169 
170     hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14);
171     hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth());
172     if ( IsBmp )
173     {
174         hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight());
175     }
176     else
177     {
178         hdr.height = wxUINT32_SWAP_ON_BE(2 * image->GetHeight());
179     }
180     hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane
181     hdr.bpp = wxUINT16_SWAP_ON_BE(bpp);
182     hdr.compression = 0; // RGB uncompressed
183     hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight());
184     hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72);  // 72dpi is standard
185     hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap
186     hdr.num_signif_clrs = 0;     // all colors are significant
187 
188     if ( IsBmp )
189     {
190         if (// VS: looks ugly but compilers tend to do ugly things with structs,
191             //     like aligning hdr.filesize's ofset to dword :(
192             // VZ: we should add padding then...
193             !stream.Write(&hdr.magic, 2) ||
194             !stream.Write(&hdr.filesize, 4) ||
195             !stream.Write(&hdr.reserved, 4) ||
196             !stream.Write(&hdr.data_offset, 4)
197            )
198         {
199             if (verbose)
200                 wxLogError(_("BMP: Couldn't write the file (Bitmap) header."));
201             return false;
202         }
203     }
204     if ( !IsMask )
205     {
206         if (
207             !stream.Write(&hdr.bih_size, 4) ||
208             !stream.Write(&hdr.width, 4) ||
209             !stream.Write(&hdr.height, 4) ||
210             !stream.Write(&hdr.planes, 2) ||
211             !stream.Write(&hdr.bpp, 2) ||
212             !stream.Write(&hdr.compression, 4) ||
213             !stream.Write(&hdr.size_of_bmp, 4) ||
214             !stream.Write(&hdr.h_res, 4) ||
215             !stream.Write(&hdr.v_res, 4) ||
216             !stream.Write(&hdr.num_clrs, 4) ||
217             !stream.Write(&hdr.num_signif_clrs, 4)
218            )
219         {
220             if (verbose)
221                 wxLogError(_("BMP: Couldn't write the file (BitmapInfo) header."));
222             return false;
223         }
224     }
225 
226     wxPalette *palette = NULL; // entries for quantized images
227     wxUint8 *rgbquad = NULL;   // for the RGBQUAD bytes for the colormap
228     wxImage *q_image = NULL;   // destination for quantized image
229 
230     // if <24bpp use quantization to reduce colors for *some* of the formats
231     if ( (format == wxBMP_1BPP) || (format == wxBMP_4BPP) ||
232          (format == wxBMP_8BPP) || (format == wxBMP_8BPP_PALETTE) )
233     {
234         // make a new palette and quantize the image
235         if (format != wxBMP_8BPP_PALETTE)
236         {
237             q_image = new wxImage();
238 
239             // I get a delete error using Quantize when desired colors > 236
240             int quantize = ((palette_size > 236) ? 236 : palette_size);
241             // fill the destination too, it gives much nicer 4bpp images
242             wxQuantize::Quantize( *image, *q_image, &palette, quantize, 0,
243                                   wxQUANTIZE_FILL_DESTINATION_IMAGE );
244         }
245         else
246         {
247 #if wxUSE_PALETTE
248             palette = new wxPalette(image->GetPalette());
249 #endif // wxUSE_PALETTE
250         }
251 
252         int i;
253         unsigned char r, g, b;
254         rgbquad = new wxUint8 [palette_size*4];
255 
256         for (i = 0; i < palette_size; i++)
257         {
258 #if wxUSE_PALETTE
259             if ( !palette->GetRGB(i, &r, &g, &b) )
260 #endif // wxUSE_PALETTE
261                 r = g = b = 0;
262 
263             rgbquad[i*4] = b;
264             rgbquad[i*4+1] = g;
265             rgbquad[i*4+2] = r;
266             rgbquad[i*4+3] = 0;
267         }
268     }
269     // make a 256 entry greyscale colormap or 2 entry black & white
270     else if ( (format == wxBMP_8BPP_GREY) || (format == wxBMP_8BPP_RED) ||
271               (format == wxBMP_1BPP_BW) )
272     {
273         rgbquad = new wxUint8 [palette_size*4];
274 
275         for ( int i = 0; i < palette_size; i++ )
276         {
277             // if 1BPP_BW then the value should be either 0 or 255
278             wxUint8 c = (wxUint8)((i > 0) && (format == wxBMP_1BPP_BW) ? 255 : i);
279 
280             rgbquad[i*4] =
281             rgbquad[i*4+1] =
282             rgbquad[i*4+2] = c;
283             rgbquad[i*4+3] = 0;
284         }
285     }
286 
287     // if the colormap was made, then it needs to be written
288     if (rgbquad)
289     {
290         if ( !IsMask )
291         {
292             if ( !stream.Write(rgbquad, palette_size*4) )
293             {
294                 if (verbose)
295                     wxLogError(_("BMP: Couldn't write RGB color map."));
296                 delete[] rgbquad;
297 #if wxUSE_PALETTE
298                 delete palette;
299 #endif // wxUSE_PALETTE
300                 delete q_image;
301                 return false;
302             }
303             }
304         delete []rgbquad;
305     }
306 
307     // pointer to the image data, use quantized if available
308     wxUint8 *data = (wxUint8*) image->GetData();
309     if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData();
310 
311     wxUint8 *buffer = new wxUint8[row_width];
312     memset(buffer, 0, row_width);
313     int y; unsigned x;
314     long int pixel;
315 
316     for (y = image->GetHeight() -1; y >= 0; y--)
317     {
318         if ( format == wxBMP_24BPP ) // 3 bytes per pixel red,green,blue
319         {
320             for ( x = 0; x < width; x++ )
321             {
322                 pixel = 3*(y*width + x);
323 
324                 buffer[3*x    ] = data[pixel+2];
325                 buffer[3*x + 1] = data[pixel+1];
326                 buffer[3*x + 2] = data[pixel];
327             }
328         }
329         else if ((format == wxBMP_8BPP) ||       // 1 byte per pixel in color
330                  (format == wxBMP_8BPP_PALETTE))
331         {
332             for (x = 0; x < width; x++)
333             {
334                 pixel = 3*(y*width + x);
335 #if wxUSE_PALETTE
336                 buffer[x] = (wxUint8)palette->GetPixel( data[pixel],
337                                                         data[pixel+1],
338                                                         data[pixel+2] );
339 #else
340                 // FIXME: what should this be? use some std palette maybe?
341                 buffer[x] = 0;
342 #endif // wxUSE_PALETTE
343             }
344         }
345         else if ( format == wxBMP_8BPP_GREY ) // 1 byte per pix, rgb ave to grey
346         {
347             for (x = 0; x < width; x++)
348             {
349                 pixel = 3*(y*width + x);
350                 buffer[x] = (wxUint8)(.299*data[pixel] +
351                                       .587*data[pixel+1] +
352                                       .114*data[pixel+2]);
353             }
354         }
355         else if ( format == wxBMP_8BPP_RED ) // 1 byte per pixel, red as greys
356         {
357             for (x = 0; x < width; x++)
358             {
359                 buffer[x] = (wxUint8)data[3*(y*width + x)];
360             }
361         }
362         else if ( format == wxBMP_4BPP ) // 4 bpp in color
363         {
364             for (x = 0; x < width; x+=2)
365             {
366                 pixel = 3*(y*width + x);
367 
368                 // fill buffer, ignore if > width
369 #if wxUSE_PALETTE
370                 buffer[x/2] = (wxUint8)(
371                     ((wxUint8)palette->GetPixel(data[pixel],
372                                                 data[pixel+1],
373                                                 data[pixel+2]) << 4) |
374                     (((x+1) > width)
375                      ? 0
376                      : ((wxUint8)palette->GetPixel(data[pixel+3],
377                                                    data[pixel+4],
378                                                    data[pixel+5]) ))    );
379 #else
380                 // FIXME: what should this be? use some std palette maybe?
381                 buffer[x/2] = 0;
382 #endif // wxUSE_PALETTE
383             }
384         }
385         else if ( format == wxBMP_1BPP ) // 1 bpp in "color"
386         {
387             for (x = 0; x < width; x+=8)
388             {
389                 pixel = 3*(y*width + x);
390 
391 #if wxUSE_PALETTE
392                 buffer[x/8] = (wxUint8)(
393                                            ((wxUint8)palette->GetPixel(data[pixel], data[pixel+1], data[pixel+2]) << 7) |
394                     (((x+1) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+3], data[pixel+4], data[pixel+5]) << 6)) |
395                     (((x+2) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+6], data[pixel+7], data[pixel+8]) << 5)) |
396                     (((x+3) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+9], data[pixel+10], data[pixel+11]) << 4)) |
397                     (((x+4) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+12], data[pixel+13], data[pixel+14]) << 3)) |
398                     (((x+5) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+15], data[pixel+16], data[pixel+17]) << 2)) |
399                     (((x+6) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+18], data[pixel+19], data[pixel+20]) << 1)) |
400                     (((x+7) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+21], data[pixel+22], data[pixel+23])     ))    );
401 #else
402                 // FIXME: what should this be? use some std palette maybe?
403                 buffer[x/8] = 0;
404 #endif // wxUSE_PALETTE
405             }
406         }
407         else if ( format == wxBMP_1BPP_BW ) // 1 bpp B&W colormap from red color ONLY
408         {
409             for (x = 0; x < width; x+=8)
410             {
411                 pixel = 3*(y*width + x);
412 
413                 buffer[x/8] = (wxUint8)(
414                                           (((wxUint8)(data[pixel]   /128.)) << 7) |
415                    (((x+1) > width) ? 0 : (((wxUint8)(data[pixel+3] /128.)) << 6)) |
416                    (((x+2) > width) ? 0 : (((wxUint8)(data[pixel+6] /128.)) << 5)) |
417                    (((x+3) > width) ? 0 : (((wxUint8)(data[pixel+9] /128.)) << 4)) |
418                    (((x+4) > width) ? 0 : (((wxUint8)(data[pixel+12]/128.)) << 3)) |
419                    (((x+5) > width) ? 0 : (((wxUint8)(data[pixel+15]/128.)) << 2)) |
420                    (((x+6) > width) ? 0 : (((wxUint8)(data[pixel+18]/128.)) << 1)) |
421                    (((x+7) > width) ? 0 : (((wxUint8)(data[pixel+21]/128.))     ))    );
422             }
423         }
424 
425         if ( !stream.Write(buffer, row_width) )
426         {
427             if (verbose)
428                 wxLogError(_("BMP: Couldn't write data."));
429             delete[] buffer;
430 #if wxUSE_PALETTE
431             delete palette;
432 #endif // wxUSE_PALETTE
433             delete q_image;
434             return false;
435         }
436     }
437     delete[] buffer;
438 #if wxUSE_PALETTE
439     delete palette;
440 #endif // wxUSE_PALETTE
441     delete q_image;
442 
443     return true;
444 }
445 
446 
447 typedef struct
448 {
449     unsigned char r, g, b;
450 }  _cmap;
451 
DoLoadDib(wxImage * image,int width,int height,int bpp,int ncolors,int comp,wxFileOffset bmpOffset,wxInputStream & stream,bool verbose,bool IsBmp,bool hasPalette)452 bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
453                              int bpp, int ncolors, int comp,
454                              wxFileOffset bmpOffset, wxInputStream& stream,
455                              bool verbose, bool IsBmp, bool hasPalette)
456 {
457     wxInt32         aDword, rmask = 0, gmask = 0, bmask = 0, amask = 0;
458     int             rshift = 0, gshift = 0, bshift = 0, ashift = 0;
459     int             rbits = 0, gbits = 0, bbits = 0, abits = 0;
460     wxInt32         dbuf[4];
461     wxInt8          bbuf[4];
462     wxUint8         aByte;
463     wxUint16        aWord;
464 
465     // allocate space for palette if needed:
466     _cmap *cmap;
467 
468     if ( bpp < 16 )
469     {
470         cmap = new _cmap[ncolors];
471         if ( !cmap )
472         {
473             if (verbose)
474                 wxLogError(_("BMP: Couldn't allocate memory."));
475             return false;
476         }
477     }
478     else
479         cmap = NULL;
480 
481     // destroy existing here instead of:
482     image->Destroy();
483     image->Create(width, height);
484 
485     unsigned char *ptr = image->GetData();
486 
487     if ( !ptr )
488     {
489         if ( verbose )
490             wxLogError( _("BMP: Couldn't allocate memory.") );
491         delete[] cmap;
492         return false;
493     }
494 
495     unsigned char *alpha;
496     if ( bpp == 32 )
497     {
498         // tell the image to allocate an alpha buffer
499         image->SetAlpha();
500         alpha = image->GetAlpha();
501         if ( !alpha )
502         {
503             if ( verbose )
504                 wxLogError(_("BMP: Couldn't allocate memory."));
505             delete[] cmap;
506             return false;
507         }
508     }
509     else // no alpha
510     {
511         alpha = NULL;
512     }
513 
514     // Reading the palette, if it exists:
515     if ( bpp < 16 && ncolors != 0 )
516     {
517         unsigned char* r = new unsigned char[ncolors];
518         unsigned char* g = new unsigned char[ncolors];
519         unsigned char* b = new unsigned char[ncolors];
520         for (int j = 0; j < ncolors; j++)
521         {
522             if (hasPalette)
523             {
524                 stream.Read(bbuf, 4);
525                 cmap[j].b = bbuf[0];
526                 cmap[j].g = bbuf[1];
527                 cmap[j].r = bbuf[2];
528 
529                 r[j] = cmap[j].r;
530                 g[j] = cmap[j].g;
531                 b[j] = cmap[j].b;
532             }
533             else
534             {
535                 //used in reading .ico file mask
536                 r[j] = cmap[j].r =
537                 g[j] = cmap[j].g =
538                 b[j] = cmap[j].b = ( j ? 255 : 0 );
539             }
540         }
541 
542 #if wxUSE_PALETTE
543         // Set the palette for the wxImage
544         image->SetPalette(wxPalette(ncolors, r, g, b));
545 #endif // wxUSE_PALETTE
546 
547         delete[] r;
548         delete[] g;
549         delete[] b;
550     }
551     else if ( bpp == 16 || bpp == 32 )
552     {
553         if ( comp == BI_BITFIELDS )
554         {
555             int bit = 0;
556             stream.Read(dbuf, 4 * 3);
557             rmask = wxINT32_SWAP_ON_BE(dbuf[0]);
558             gmask = wxINT32_SWAP_ON_BE(dbuf[1]);
559             bmask = wxINT32_SWAP_ON_BE(dbuf[2]);
560             // find shift amount (Least significant bit of mask)
561             for (bit = bpp-1; bit>=0; bit--)
562             {
563                 if (bmask & (1 << bit))
564                     bshift = bit;
565                 if (gmask & (1 << bit))
566                     gshift = bit;
567                 if (rmask & (1 << bit))
568                     rshift = bit;
569             }
570             // Find number of bits in mask (MSB-LSB+1)
571             for (bit = 0; bit < bpp; bit++)
572             {
573                 if (bmask & (1 << bit))
574                     bbits = bit-bshift+1;
575                 if (gmask & (1 << bit))
576                     gbits = bit-gshift+1;
577                 if (rmask & (1 << bit))
578                     rbits = bit-rshift+1;
579             }
580         }
581         else if ( bpp == 16 )
582         {
583             rmask = 0x7C00;
584             gmask = 0x03E0;
585             bmask = 0x001F;
586             rshift = 10;
587             gshift = 5;
588             bshift = 0;
589             rbits = 5;
590             gbits = 5;
591             bbits = 5;
592         }
593         else if ( bpp == 32 )
594         {
595             rmask = 0x00FF0000;
596             gmask = 0x0000FF00;
597             bmask = 0x000000FF;
598             amask = 0xFF000000;
599 
600             ashift = 24;
601             rshift = 16;
602             gshift = 8;
603             bshift = 0;
604             abits = 8;
605             rbits = 8;
606             gbits = 8;
607             bbits = 8;
608         }
609     }
610 
611     /*
612      * Reading the image data
613      */
614     if ( IsBmp )
615         stream.SeekI(bmpOffset); // else icon, just carry on
616 
617     unsigned char *data = ptr;
618 
619     /* set the whole image to the background color */
620     if ( bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8) )
621     {
622         for (int i = 0; i < width * height; i++)
623         {
624             *ptr++ = cmap[0].r;
625             *ptr++ = cmap[0].g;
626             *ptr++ = cmap[0].b;
627         }
628         ptr = data;
629     }
630 
631     int linesize = ((width * bpp + 31) / 32) * 4;
632 
633     /* BMPs are stored upside down */
634     for ( int line = (height - 1); line >= 0; line-- )
635     {
636         int linepos = 0;
637         for ( int column = 0; column < width ; )
638         {
639             if ( bpp < 16 )
640             {
641                 linepos++;
642                 aByte = stream.GetC();
643                 if ( bpp == 1 )
644                 {
645                     for (int bit = 0; bit < 8 && column < width; bit++)
646                     {
647                         int index = ((aByte & (0x80 >> bit)) ? 1 : 0);
648                         ptr[poffset] = cmap[index].r;
649                         ptr[poffset + 1] = cmap[index].g;
650                         ptr[poffset + 2] = cmap[index].b;
651                         column++;
652                     }
653                 }
654                 else if ( bpp == 4 )
655                 {
656                     if ( comp == BI_RLE4 )
657                     {
658                         wxUint8 first;
659                         first = aByte;
660                         aByte = stream.GetC();
661                         if ( first == 0 )
662                         {
663                             if ( aByte == 0 )
664                             {
665                                 if ( column > 0 )
666                                     column = width;
667                             }
668                             else if ( aByte == 1 )
669                             {
670                                 column = width;
671                                 line = -1;
672                             }
673                             else if ( aByte == 2 )
674                             {
675                                 aByte = stream.GetC();
676                                 column += aByte;
677                                 linepos = column * bpp / 4;
678                                 aByte = stream.GetC();
679                                 line -= aByte; // upside down
680                             }
681                             else
682                             {
683                                 int absolute = aByte;
684                                 wxUint8 nibble[2] ;
685                                 int readBytes = 0 ;
686                                 for (int k = 0; k < absolute; k++)
687                                 {
688                                     if ( !(k % 2 ) )
689                                     {
690                                         ++readBytes ;
691                                         aByte = stream.GetC();
692                                         nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ;
693                                         nibble[1] = (wxUint8)( aByte & 0x0F ) ;
694                                     }
695                                     ptr[poffset    ] = cmap[nibble[k%2]].r;
696                                     ptr[poffset + 1] = cmap[nibble[k%2]].g;
697                                     ptr[poffset + 2] = cmap[nibble[k%2]].b;
698                                     column++;
699                                     if ( k % 2 )
700                                         linepos++;
701                                 }
702                                 if ( readBytes & 0x01 )
703                                     aByte = stream.GetC();
704                             }
705                         }
706                         else
707                         {
708                             wxUint8 nibble[2] ;
709                             nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ;
710                             nibble[1] = (wxUint8)( aByte & 0x0F ) ;
711 
712                             for ( int l = 0; l < first && column < width; l++ )
713                             {
714                                 ptr[poffset    ] = cmap[nibble[l%2]].r;
715                                 ptr[poffset + 1] = cmap[nibble[l%2]].g;
716                                 ptr[poffset + 2] = cmap[nibble[l%2]].b;
717                                 column++;
718                                 if ( l % 2 )
719                                     linepos++;
720                             }
721                         }
722                     }
723                     else
724                     {
725                         for (int nibble = 0; nibble < 2 && column < width; nibble++)
726                         {
727                             int index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
728                             if ( index >= 16 )
729                                 index = 15;
730                             ptr[poffset] = cmap[index].r;
731                             ptr[poffset + 1] = cmap[index].g;
732                             ptr[poffset + 2] = cmap[index].b;
733                             column++;
734                         }
735                     }
736                 }
737                 else if ( bpp == 8 )
738                 {
739                     if ( comp == BI_RLE8 )
740                     {
741                         unsigned char first;
742                         first = aByte;
743                         aByte = stream.GetC();
744                         if ( first == 0 )
745                         {
746                             if ( aByte == 0 )
747                             {
748                                 /* column = width; */
749                             }
750                             else if ( aByte == 1 )
751                             {
752                                 column = width;
753                                 line = -1;
754                             }
755                             else if ( aByte == 2 )
756                             {
757                                 aByte = stream.GetC();
758                                 column += aByte;
759                                 linepos = column * bpp / 8;
760                                 aByte = stream.GetC();
761                                 line += aByte;
762                             }
763                             else
764                             {
765                                 int absolute = aByte;
766                                 for (int k = 0; k < absolute; k++)
767                                 {
768                                     linepos++;
769                                     aByte = stream.GetC();
770                                     ptr[poffset    ] = cmap[aByte].r;
771                                     ptr[poffset + 1] = cmap[aByte].g;
772                                     ptr[poffset + 2] = cmap[aByte].b;
773                                     column++;
774                                 }
775                                 if ( absolute & 0x01 )
776                                     aByte = stream.GetC();
777                             }
778                         }
779                         else
780                         {
781                             for ( int l = 0; l < first && column < width; l++ )
782                             {
783                                 ptr[poffset    ] = cmap[aByte].r;
784                                 ptr[poffset + 1] = cmap[aByte].g;
785                                 ptr[poffset + 2] = cmap[aByte].b;
786                                 column++;
787                                 linepos++;
788                             }
789                         }
790                     }
791                     else
792                     {
793                         ptr[poffset    ] = cmap[aByte].r;
794                         ptr[poffset + 1] = cmap[aByte].g;
795                         ptr[poffset + 2] = cmap[aByte].b;
796                         column++;
797                         // linepos += size;    seems to be wrong, RR
798                     }
799                 }
800             }
801             else if ( bpp == 24 )
802             {
803                 stream.Read(bbuf, 3);
804                 linepos += 3;
805                 ptr[poffset    ] = (unsigned char)bbuf[2];
806                 ptr[poffset + 1] = (unsigned char)bbuf[1];
807                 ptr[poffset + 2] = (unsigned char)bbuf[0];
808                 column++;
809             }
810             else if ( bpp == 16 )
811             {
812                 unsigned char temp;
813                 stream.Read(&aWord, 2);
814                 aWord = wxUINT16_SWAP_ON_BE(aWord);
815                 linepos += 2;
816                 /* use the masks and calculated amonut of shift
817                    to retrieve the color data out of the word.  Then
818                    shift it left by (8 - number of bits) such that
819                    the image has the proper dynamic range */
820                 temp = (unsigned char)((aWord & rmask) >> rshift << (8-rbits));
821                 ptr[poffset] = temp;
822                 temp = (unsigned char)((aWord & gmask) >> gshift << (8-gbits));
823                 ptr[poffset + 1] = temp;
824                 temp = (unsigned char)((aWord & bmask) >> bshift << (8-bbits));
825                 ptr[poffset + 2] = temp;
826                 column++;
827             }
828             else
829             {
830                 unsigned char temp;
831                 stream.Read(&aDword, 4);
832                 aDword = wxINT32_SWAP_ON_BE(aDword);
833                 linepos += 4;
834                 temp = (unsigned char)((aDword & rmask) >> rshift);
835                 ptr[poffset] = temp;
836                 temp = (unsigned char)((aDword & gmask) >> gshift);
837                 ptr[poffset + 1] = temp;
838                 temp = (unsigned char)((aDword & bmask) >> bshift);
839                 ptr[poffset + 2] = temp;
840                 if ( alpha )
841                 {
842                     temp = (unsigned char)((aDword & amask) >> ashift);
843                     alpha[line * width + column] = temp;
844                 }
845                 column++;
846             }
847         }
848         while ( (linepos < linesize) && (comp != 1) && (comp != 2) )
849         {
850             stream.Read(&aByte, 1);
851             linepos += 1;
852             if ( !stream )
853                 break;
854         }
855     }
856 
857     delete[] cmap;
858 
859     image->SetMask(false);
860 
861     const wxStreamError err = stream.GetLastError();
862     return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF;
863 }
864 
LoadDib(wxImage * image,wxInputStream & stream,bool verbose,bool IsBmp)865 bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream,
866                            bool verbose, bool IsBmp)
867 {
868     wxUint16        aWord;
869     wxInt32         dbuf[4];
870     wxInt8          bbuf[4];
871 
872     wxFileOffset offset = 0; // keep gcc quiet
873     if ( IsBmp )
874     {
875         // read the header off the .BMP format file
876 
877         offset = stream.TellI();
878         if (offset == wxInvalidOffset)
879             offset = 0;
880 
881         stream.Read(bbuf, 2);
882         stream.Read(dbuf, 16);
883     }
884     else
885     {
886         stream.Read(dbuf, 4);
887     }
888     #if 0 // unused
889         wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]);
890     #endif
891     offset = offset + wxINT32_SWAP_ON_BE(dbuf[2]);
892 
893     stream.Read(dbuf, 4 * 2);
894     int width = wxINT32_SWAP_ON_BE((int)dbuf[0]);
895     int height = wxINT32_SWAP_ON_BE((int)dbuf[1]);
896     if ( !IsBmp)height = height  / 2; // for icons divide by 2
897 
898     if ( width > 32767 )
899     {
900         if (verbose)
901             wxLogError( _("DIB Header: Image width > 32767 pixels for file.") );
902         return false;
903     }
904     if ( height > 32767 )
905     {
906         if (verbose)
907             wxLogError( _("DIB Header: Image height > 32767 pixels for file.") );
908         return false;
909     }
910 
911     stream.Read(&aWord, 2);
912     /*
913             TODO
914             int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
915         */
916     stream.Read(&aWord, 2);
917     int bpp = wxUINT16_SWAP_ON_BE((int)aWord);
918     if ( bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 )
919     {
920         if (verbose)
921             wxLogError( _("DIB Header: Unknown bitdepth in file.") );
922         return false;
923     }
924 
925     stream.Read(dbuf, 4 * 4);
926     int comp = wxINT32_SWAP_ON_BE((int)dbuf[0]);
927     if ( comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 &&
928          comp != BI_BITFIELDS )
929     {
930         if (verbose)
931             wxLogError( _("DIB Header: Unknown encoding in file.") );
932         return false;
933     }
934 
935     stream.Read(dbuf, 4 * 2);
936     int ncolors = wxINT32_SWAP_ON_BE( (int)dbuf[0] );
937     if (ncolors == 0)
938         ncolors = 1 << bpp;
939     /* some more sanity checks */
940     if (((comp == BI_RLE4) && (bpp != 4)) ||
941         ((comp == BI_RLE8) && (bpp != 8)) ||
942         ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
943     {
944         if (verbose)
945             wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") );
946         return false;
947     }
948 
949     //read DIB; this is the BMP image or the XOR part of an icon image
950     if ( !DoLoadDib(image, width, height, bpp, ncolors, comp, offset, stream,
951                     verbose, IsBmp, true) )
952     {
953         if (verbose)
954             wxLogError( _("Error in reading image DIB.") );
955         return false;
956     }
957 
958     if ( !IsBmp )
959     {
960         //read Icon mask which is monochrome
961         //there is no palette, so we will create one
962         wxImage mask;
963         if ( !DoLoadDib(&mask, width, height, 1, 2, BI_RGB, offset, stream,
964                         verbose, IsBmp, false) )
965         {
966             if (verbose)
967                 wxLogError( _("ICO: Error in reading mask DIB.") );
968             return false;
969         }
970         image->SetMaskFromImage(mask, 255, 255, 255);
971 
972     }
973 
974     return true;
975 }
976 
LoadFile(wxImage * image,wxInputStream & stream,bool verbose,int WXUNUSED (index))977 bool wxBMPHandler::LoadFile(wxImage *image, wxInputStream& stream,
978                             bool verbose, int WXUNUSED(index))
979 {
980     // Read a single DIB fom the file:
981     return LoadDib(image, stream, verbose, true/*isBmp*/);
982 }
983 
DoCanRead(wxInputStream & stream)984 bool wxBMPHandler::DoCanRead(wxInputStream& stream)
985 {
986     unsigned char hdr[2];
987 
988     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
989         return false;
990 
991     // do we have the BMP file signature?
992     return hdr[0] == 'B' && hdr[1] == 'M';
993 }
994 
995 #endif // wxUSE_STREAMS
996 
997 
998 #if wxUSE_ICO_CUR
999 //-----------------------------------------------------------------------------
1000 // wxICOHandler
1001 //-----------------------------------------------------------------------------
1002 
1003 IMPLEMENT_DYNAMIC_CLASS(wxICOHandler, wxBMPHandler)
1004 
1005 #if wxUSE_STREAMS
1006 
1007 struct ICONDIRENTRY
1008 {
1009     wxUint8         bWidth;               // Width of the image
1010     wxUint8         bHeight;              // Height of the image (times 2)
1011     wxUint8         bColorCount;          // Number of colors in image (0 if >=8bpp)
1012     wxUint8         bReserved;            // Reserved
1013 
1014     // these two are different in icons and cursors:
1015                                           // icon           or  cursor
1016     wxUint16        wPlanes;              // Color Planes   or  XHotSpot
1017     wxUint16        wBitCount;            // Bits per pixel or  YHotSpot
1018 
1019     wxUint32        dwBytesInRes;         // how many bytes in this resource?
1020     wxUint32        dwImageOffset;        // where in the file is this image
1021 };
1022 
1023 struct ICONDIR
1024 {
1025     wxUint16     idReserved;   // Reserved
1026     wxUint16     idType;       // resource type (1 for icons, 2 for cursors)
1027     wxUint16     idCount;      // how many images?
1028 };
1029 
1030 
SaveFile(wxImage * image,wxOutputStream & stream,bool verbose)1031 bool wxICOHandler::SaveFile(wxImage *image,
1032                             wxOutputStream& stream,
1033                             bool verbose)
1034 
1035 {
1036     //sanity check; icon must be less than 127 pixels high and 255 wide
1037     if ( image->GetHeight () > 127 )
1038     {
1039         if ( verbose )
1040             wxLogError(_("ICO: Image too tall for an icon."));
1041         return false;
1042     }
1043     if ( image->GetWidth () > 255 )
1044     {
1045         if ( verbose )
1046             wxLogError(_("ICO: Image too wide for an icon."));
1047         return false;
1048     }
1049 
1050     const int images = 1; // only generate one image
1051 
1052     // VS: This is a hack of sort - since ICO and CUR files are almost
1053     //     identical, we have all the meat in wxICOHandler and check for
1054     //     the actual (handler) type when the code has to distinguish between
1055     //     the two formats
1056     int type = (this->GetType() == wxBITMAP_TYPE_CUR) ? 2 : 1;
1057 
1058     // write a header, (ICONDIR)
1059     // Calculate the header size
1060     wxUint32 offset = 3 * sizeof(wxUint16);
1061 
1062     ICONDIR IconDir;
1063     IconDir.idReserved = 0;
1064     IconDir.idType = wxUINT16_SWAP_ON_BE((wxUint16)type);
1065     IconDir.idCount = wxUINT16_SWAP_ON_BE((wxUint16)images);
1066     stream.Write(&IconDir.idReserved, sizeof(IconDir.idReserved));
1067     stream.Write(&IconDir.idType, sizeof(IconDir.idType));
1068     stream.Write(&IconDir.idCount, sizeof(IconDir.idCount));
1069     if ( !stream.IsOk() )
1070     {
1071         if ( verbose )
1072             wxLogError(_("ICO: Error writing the image file!"));
1073         return false;
1074     }
1075 
1076     // for each iamage write a description ICONDIRENTRY:
1077     ICONDIRENTRY icondirentry;
1078     for (int img = 0; img < images; img++)
1079     {
1080         wxImage mask;
1081 
1082         if ( image->HasMask() )
1083         {
1084             // make another image with black/white:
1085             mask = image->ConvertToMono (image->GetMaskRed(), image->GetMaskGreen(), image->GetMaskBlue() );
1086 
1087             // now we need to change the masked regions to black:
1088             unsigned char r = image->GetMaskRed();
1089             unsigned char g = image->GetMaskGreen();
1090             unsigned char b = image->GetMaskBlue();
1091             if ( (r != 0) || (g != 0) || (b != 0) )
1092             {
1093                 // Go round and apply black to the masked bits:
1094                 int i, j;
1095                 for (i = 0; i < mask.GetWidth(); i++)
1096                 {
1097                     for (j = 0; j < mask.GetHeight(); j++)
1098                     {
1099                         if ((r == mask.GetRed(i, j)) &&
1100                             (g == mask.GetGreen(i, j))&&
1101                             (b == mask.GetBlue(i, j)) )
1102                                 image->SetRGB(i, j, 0, 0, 0 );
1103                     }
1104                 }
1105             }
1106         }
1107         else
1108         {
1109             // just make a black mask all over:
1110             mask = image->Copy();
1111             int i, j;
1112             for (i = 0; i < mask.GetWidth(); i++)
1113                 for (j = 0; j < mask.GetHeight(); j++)
1114                     mask.SetRGB(i, j, 0, 0, 0 );
1115         }
1116         // Set the formats for image and mask
1117         // (Windows never saves with more than 8 colors):
1118         image->SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP);
1119 
1120         // monochome bitmap:
1121         mask.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_1BPP_BW);
1122         bool IsBmp = false;
1123         bool IsMask = false;
1124 
1125         //calculate size and offset of image and mask
1126         wxCountingOutputStream cStream;
1127         bool bResult = SaveDib(image, cStream, verbose, IsBmp, IsMask);
1128         if ( !bResult )
1129         {
1130             if ( verbose )
1131                 wxLogError(_("ICO: Error writing the image file!"));
1132             return false;
1133         }
1134         IsMask = true;
1135 
1136         bResult = SaveDib(&mask, cStream, verbose, IsBmp, IsMask);
1137         if ( !bResult )
1138         {
1139             if ( verbose )
1140                 wxLogError(_("ICO: Error writing the image file!"));
1141             return false;
1142         }
1143         wxUint32 Size = cStream.GetSize();
1144 
1145         // wxCountingOutputStream::IsOk() always returns true for now and this
1146         // "if" provokes VC++ warnings in optimized build
1147 #if 0
1148         if ( !cStream.Ok() )
1149         {
1150             if ( verbose )
1151                 wxLogError(_("ICO: Error writing the image file!"));
1152             return false;
1153         }
1154 #endif // 0
1155 
1156         offset = offset + sizeof(ICONDIRENTRY);
1157 
1158         icondirentry.bWidth = (wxUint8)image->GetWidth();
1159         icondirentry.bHeight = (wxUint8)(2 * image->GetHeight());
1160         icondirentry.bColorCount = 0;
1161         icondirentry.bReserved = 0;
1162         icondirentry.wPlanes = wxUINT16_SWAP_ON_BE(1);
1163         icondirentry.wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP);
1164         if ( type == 2 /*CUR*/)
1165         {
1166             int hx = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ?
1167                          image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X) :
1168                          image->GetWidth() / 2;
1169             int hy = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ?
1170                          image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y) :
1171                          image->GetHeight() / 2;
1172 
1173             // actually write the values of the hot spot here:
1174             icondirentry.wPlanes = wxUINT16_SWAP_ON_BE((wxUint16)hx);
1175             icondirentry.wBitCount = wxUINT16_SWAP_ON_BE((wxUint16)hy);
1176         }
1177         icondirentry.dwBytesInRes = wxUINT32_SWAP_ON_BE(Size);
1178         icondirentry.dwImageOffset = wxUINT32_SWAP_ON_BE(offset);
1179 
1180         // increase size to allow for the data written:
1181         offset += Size;
1182 
1183         // write to stream:
1184         stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth));
1185         stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight));
1186         stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount));
1187         stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved));
1188         stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes));
1189         stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount));
1190         stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes));
1191         stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset));
1192         if ( !stream.IsOk() )
1193         {
1194             if ( verbose )
1195                 wxLogError(_("ICO: Error writing the image file!"));
1196             return false;
1197         }
1198 
1199         // actually save it:
1200         IsMask = false;
1201         bResult = SaveDib(image, stream, verbose, IsBmp, IsMask);
1202         if ( !bResult )
1203         {
1204             if ( verbose )
1205                 wxLogError(_("ICO: Error writing the image file!"));
1206             return false;
1207         }
1208         IsMask = true;
1209 
1210         bResult = SaveDib(&mask, stream, verbose, IsBmp, IsMask);
1211         if ( !bResult )
1212         {
1213             if ( verbose )
1214                 wxLogError(_("ICO: Error writing the image file!"));
1215             return false;
1216         }
1217 
1218     } // end of for loop
1219 
1220     return true;
1221 }
1222 
LoadFile(wxImage * image,wxInputStream & stream,bool verbose,int index)1223 bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream,
1224                             bool verbose, int index)
1225 {
1226     stream.SeekI(0);
1227     return DoLoadFile(image, stream, verbose, index);
1228 }
1229 
DoLoadFile(wxImage * image,wxInputStream & stream,bool WXUNUSED (verbose),int index)1230 bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
1231                             bool WXUNUSED(verbose), int index)
1232 {
1233     bool bResult wxDUMMY_INITIALIZE(false);
1234     bool IsBmp = false;
1235 
1236     ICONDIR IconDir;
1237 
1238     wxFileOffset iPos = stream.TellI();
1239     stream.Read(&IconDir, sizeof(IconDir));
1240     wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
1241     // nType is 1 for Icons, 2 for Cursors:
1242     wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType);
1243 
1244     // loop round the icons and choose the best one:
1245     ICONDIRENTRY *pIconDirEntry = new ICONDIRENTRY[nIcons];
1246     ICONDIRENTRY *pCurrentEntry = pIconDirEntry;
1247     int wMax = 0;
1248     int colmax = 0;
1249     int iSel = wxNOT_FOUND;
1250 
1251     for (int i = 0; i < nIcons; i++ )
1252     {
1253         stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY));
1254         // bHeight and bColorCount are wxUint8
1255         if ( pCurrentEntry->bWidth >= wMax )
1256         {
1257             // see if we have more colors, ==0 indicates > 8bpp:
1258             if ( pCurrentEntry->bColorCount == 0 )
1259                 pCurrentEntry->bColorCount = 255;
1260             if ( pCurrentEntry->bColorCount >= colmax )
1261             {
1262                 iSel = i;
1263                 wMax = pCurrentEntry->bWidth;
1264                 colmax = pCurrentEntry->bColorCount;
1265             }
1266         }
1267         pCurrentEntry++;
1268     }
1269 
1270     if ( index != -1 )
1271     {
1272         // VS: Note that we *have* to run the loop above even if index != -1, because
1273         //     it reads ICONDIRENTRies.
1274         iSel = index;
1275     }
1276 
1277     if ( iSel == wxNOT_FOUND || iSel < 0 || iSel >= nIcons )
1278     {
1279         wxLogError(_("ICO: Invalid icon index."));
1280         bResult = false;
1281     }
1282     else
1283     {
1284         // seek to selected icon:
1285         pCurrentEntry = pIconDirEntry + iSel;
1286         stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart);
1287         bResult = LoadDib(image, stream, true, IsBmp);
1288         bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI);
1289         if ( bResult && bIsCursorType && nType == 2 )
1290         {
1291             // it is a cursor, so let's set the hotspot:
1292             image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, wxUINT16_SWAP_ON_BE(pCurrentEntry->wPlanes));
1293             image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount));
1294         }
1295     }
1296     delete[] pIconDirEntry;
1297     return bResult;
1298 }
1299 
GetImageCount(wxInputStream & stream)1300 int wxICOHandler::GetImageCount(wxInputStream& stream)
1301 {
1302     ICONDIR IconDir;
1303     wxFileOffset iPos = stream.TellI();
1304     stream.SeekI(0);
1305     stream.Read(&IconDir, sizeof(IconDir));
1306     wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
1307     stream.SeekI(iPos);
1308     return (int)nIcons;
1309 }
1310 
DoCanRead(wxInputStream & stream)1311 bool wxICOHandler::DoCanRead(wxInputStream& stream)
1312 {
1313     stream.SeekI(0);
1314     unsigned char hdr[4];
1315     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
1316         return false;
1317 
1318     // hdr[2] is one for an icon and two for a cursor
1319     return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0';
1320 }
1321 
1322 #endif // wxUSE_STREAMS
1323 
1324 
1325 //-----------------------------------------------------------------------------
1326 // wxCURHandler
1327 //-----------------------------------------------------------------------------
1328 
IMPLEMENT_DYNAMIC_CLASS(wxCURHandler,wxICOHandler)1329 IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler)
1330 
1331 #if wxUSE_STREAMS
1332 
1333 bool wxCURHandler::DoCanRead(wxInputStream& stream)
1334 {
1335     stream.SeekI(0);
1336     unsigned char hdr[4];
1337     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
1338         return false;
1339 
1340     // hdr[2] is one for an icon and two for a cursor
1341     return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0';
1342 }
1343 
1344 #endif // wxUSE_STREAMS
1345 
1346 //-----------------------------------------------------------------------------
1347 // wxANIHandler
1348 //-----------------------------------------------------------------------------
1349 
IMPLEMENT_DYNAMIC_CLASS(wxANIHandler,wxCURHandler)1350 IMPLEMENT_DYNAMIC_CLASS(wxANIHandler, wxCURHandler)
1351 
1352 #if wxUSE_STREAMS
1353 
1354 bool wxANIHandler::LoadFile(wxImage *image, wxInputStream& stream,
1355                             bool WXUNUSED(verbose), int index)
1356 {
1357     wxANIDecoder decoder;
1358     if (!decoder.Load(stream))
1359         return false;
1360 
1361     return decoder.ConvertToImage(index != -1 ? (size_t)index : 0, image);
1362 }
1363 
DoCanRead(wxInputStream & stream)1364 bool wxANIHandler::DoCanRead(wxInputStream& stream)
1365 {
1366     wxANIDecoder decod;
1367     return decod.CanRead(stream);
1368 }
1369 
GetImageCount(wxInputStream & stream)1370 int wxANIHandler::GetImageCount(wxInputStream& stream)
1371 {
1372     wxANIDecoder decoder;
1373     if (!decoder.Load(stream))
1374         return wxNOT_FOUND;
1375 
1376     return decoder.GetFrameCount();
1377 }
1378 
1379 #endif // wxUSE_STREAMS
1380 
1381 #endif // wxUSE_ICO_CUR
1382 
1383 #endif // wxUSE_IMAGE
1384