home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / imagbmp.cpp < prev    next >
C/C++ Source or Header  |  2002-09-06  |  47KB  |  1,413 lines

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