home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / imagbmp.cpp < prev    next >
C/C++ Source or Header  |  2002-11-22  |  50KB  |  1,476 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.2.3 2002/11/18 16:04:19 CE 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.                         wxUint8 first;
  635.                         first = aByte;
  636.                         aByte = stream.GetC();
  637.                         if ( first == 0 )
  638.                         {
  639.                             if ( aByte == 0 )
  640.                             {
  641.                                 if ( column > 0 )
  642.                                     column = width;
  643.                             }
  644.                             else if ( aByte == 1 )
  645.                             {
  646.                                 column = width;
  647.                                 line = -1;
  648.                             }
  649.                             else if ( aByte == 2 )
  650.                             {
  651.                                 aByte = stream.GetC();
  652.                                 column += aByte;
  653.                                 linepos = column * bpp / 4;
  654.                                 aByte = stream.GetC();
  655.                                 line -= aByte; // upside down
  656.                             }
  657.                             else
  658.                             {
  659.                                 int absolute = aByte;
  660.                                 wxUint8 nibble[2] ;
  661.                                 int readBytes = 0 ;
  662.                                 for (int k = 0; k < absolute; k++)
  663.                                 {
  664.                                     if ( !(k % 2 ) )
  665.                                     {
  666.                                         ++readBytes ;
  667.                                         aByte = stream.GetC();
  668.                                         nibble[0] = ( (aByte & 0xF0) >> 4 ) ;
  669.                                         nibble[1] = ( aByte & 0x0F ) ;
  670.                                     }
  671.                                     ptr[poffset    ] = cmap[nibble[k%2]].r;
  672.                                     ptr[poffset + 1] = cmap[nibble[k%2]].g;
  673.                                     ptr[poffset + 2] = cmap[nibble[k%2]].b;
  674.                                     column++;
  675.                                     if ( k % 2 )
  676.                                         linepos++;
  677.                                 }
  678.                                 if ( readBytes & 0x01 )
  679.                                     aByte = stream.GetC();
  680.                             }
  681.                         }
  682.                         else
  683.                         {
  684.                             wxUint8 nibble[2] ;
  685.                             nibble[0] = ( (aByte & 0xF0) >> 4 ) ;
  686.                             nibble[1] = ( aByte & 0x0F ) ;
  687.  
  688.                             for ( int l = 0; l < first && column < width; l++ )
  689.                             {
  690.                                 ptr[poffset    ] = cmap[nibble[l%2]].r;
  691.                                 ptr[poffset + 1] = cmap[nibble[l%2]].g;
  692.                                 ptr[poffset + 2] = cmap[nibble[l%2]].b;
  693.                                 column++;
  694.                                 if ( l % 2 )
  695.                                     linepos++;
  696.                             }
  697.                         }
  698.                     }
  699.                     else
  700.                     {
  701.                         int nibble = 0;
  702.                         for (nibble = 0; nibble < 2 && column < width; nibble++)
  703.                         {
  704.                             index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
  705.                             if ( index >= 16 )
  706.                                 index = 15;
  707.                             ptr[poffset] = cmap[index].r;
  708.                             ptr[poffset + 1] = cmap[index].g;
  709.                             ptr[poffset + 2] = cmap[index].b;
  710.                             column++;
  711.                         }
  712.                     }
  713.                 }
  714.                 else if ( bpp == 8 )
  715.                 {
  716.                     if ( comp == BI_RLE8 )
  717.                     {
  718.                         unsigned char first;
  719.                         first = aByte;
  720.                         aByte = stream.GetC();
  721.                         if ( first == 0 )
  722.                         {
  723.                             if ( aByte == 0 )
  724.                             {
  725.                                 /* column = width; */
  726.                             }
  727.                             else if ( aByte == 1 )
  728.                             {
  729.                                 column = width;
  730.                                 line = -1;
  731.                             }
  732.                             else if ( aByte == 2 )
  733.                             {
  734.                                 aByte = stream.GetC();
  735.                                 column += aByte;
  736.                                 linepos = column * bpp / 8;
  737.                                 aByte = stream.GetC();
  738.                                 line += aByte;
  739.                             }
  740.                             else
  741.                             {
  742.                                 int absolute = aByte;
  743.                                 for (int k = 0; k < absolute; k++)
  744.                                 {
  745.                                     linepos++;
  746.                                     aByte = stream.GetC();
  747.                                     ptr[poffset    ] = cmap[aByte].r;
  748.                                     ptr[poffset + 1] = cmap[aByte].g;
  749.                                     ptr[poffset + 2] = cmap[aByte].b;
  750.                                     column++;
  751.                                 }
  752.                                 if ( absolute & 0x01 )
  753.                                     aByte = stream.GetC();
  754.                             }
  755.                         }
  756.                         else
  757.                         {
  758.                             for ( int l = 0; l < first && column < width; l++ )
  759.                             {
  760.                                 ptr[poffset    ] = cmap[aByte].r;
  761.                                 ptr[poffset + 1] = cmap[aByte].g;
  762.                                 ptr[poffset + 2] = cmap[aByte].b;
  763.                                 column++;
  764.                                 linepos++;
  765.                             }
  766.                         }
  767.                     }
  768.                     else
  769.                     {
  770.                         ptr[poffset    ] = cmap[aByte].r;
  771.                         ptr[poffset + 1] = cmap[aByte].g;
  772.                         ptr[poffset + 2] = cmap[aByte].b;
  773.                         column++;
  774.                         // linepos += size;    seems to be wrong, RR
  775.                     }
  776.                 }
  777.             }
  778.             else if ( bpp == 24 )
  779.             {
  780.                 stream.Read(bbuf, 3);
  781.                 linepos += 3;
  782.                 ptr[poffset    ] = (unsigned char)bbuf[2];
  783.                 ptr[poffset + 1] = (unsigned char)bbuf[1];
  784.                 ptr[poffset + 2] = (unsigned char)bbuf[0];
  785.                 column++;
  786.             }
  787.             else if ( bpp == 16 )
  788.             {
  789.                 unsigned char temp;
  790.                 stream.Read(&aWord, 2);
  791.                 aWord = wxUINT16_SWAP_ON_BE(aWord);
  792.                 linepos += 2;
  793.                 /* use the masks and calculated amonut of shift
  794.                    to retrieve the color data out of the word.  Then
  795.                    shift it left by (8 - number of bits) such that
  796.                    the image has the proper dynamic range */
  797.                 temp = (aWord & rmask) >> rshift << (8-rbits);
  798.                 ptr[poffset] = temp;
  799.                 temp = (aWord & gmask) >> gshift << (8-gbits);
  800.                 ptr[poffset + 1] = temp;
  801.                 temp = (aWord & bmask) >> bshift << (8-bbits);
  802.                 ptr[poffset + 2] = temp;
  803.                 column++;
  804.             }
  805.             else
  806.             {
  807.                 unsigned char temp;
  808.                 stream.Read(&aDword, 4);
  809.                 aDword = wxINT32_SWAP_ON_BE(aDword);
  810.                 linepos += 4;
  811.                 temp = (aDword & rmask) >> rshift;
  812.                 ptr[poffset] = temp;
  813.                 temp = (aDword & gmask) >> gshift;
  814.                 ptr[poffset + 1] = temp;
  815.                 temp = (aDword & bmask) >> bshift;
  816.                 ptr[poffset + 2] = temp;
  817.                 column++;
  818.             }
  819.         }
  820.         while ( (linepos < linesize) && (comp != 1) && (comp != 2) )
  821.         {
  822.             stream.Read(&aByte, 1);
  823.             linepos += 1;
  824.             if ( !stream )
  825.                 break;
  826.         }
  827.     }
  828.  
  829.     delete[] cmap;
  830.  
  831.     image->SetMask(FALSE);
  832.  
  833.     const wxStreamError err = stream.GetLastError();
  834.     return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF;
  835. }
  836.  
  837. bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream,
  838.                            bool verbose, bool IsBmp)
  839. {
  840.     wxUint16        aWord;
  841.     wxInt32         dbuf[4];
  842.     wxInt8          bbuf[4];
  843.     off_t           offset;
  844.  
  845.     offset = 0; // keep gcc quiet
  846.     if ( IsBmp )
  847.     {
  848.         // read the header off the .BMP format file
  849.  
  850.         offset = stream.TellI();
  851.         if (offset == wxInvalidOffset) offset = 0;
  852.  
  853.         stream.Read(bbuf, 2);
  854.         stream.Read(dbuf, 16);
  855.     }
  856.     else
  857.     {
  858.         stream.Read(dbuf, 4);
  859.     }
  860.     #if 0 // unused
  861.         wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]);
  862.     #endif
  863.     offset = offset + wxINT32_SWAP_ON_BE(dbuf[2]);
  864.  
  865.     stream.Read(dbuf, 4 * 2);
  866.     int width = (int)wxINT32_SWAP_ON_BE(dbuf[0]);
  867.     int height = (int)wxINT32_SWAP_ON_BE(dbuf[1]);
  868.     if ( !IsBmp)height = height  / 2; // for icons divide by 2
  869.  
  870.     if ( width > 32767 )
  871.     {
  872.         if (verbose)
  873.             wxLogError( _("DIB Header: Image width > 32767 pixels for file.") );
  874.         return FALSE;
  875.     }
  876.     if ( height > 32767 )
  877.     {
  878.         if (verbose)
  879.             wxLogError( _("DIB Header: Image height > 32767 pixels for file.") );
  880.         return FALSE;
  881.     }
  882.  
  883.     stream.Read(&aWord, 2);
  884.     /*
  885.             TODO
  886.             int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
  887.         */
  888.     stream.Read(&aWord, 2);
  889.     int bpp = (int)wxUINT16_SWAP_ON_BE(aWord);
  890.     if ( bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 )
  891.     {
  892.         if (verbose)
  893.             wxLogError( _("DIB Header: Unknown bitdepth in file.") );
  894.         return FALSE;
  895.     }
  896.  
  897.     stream.Read(dbuf, 4 * 4);
  898.     int comp = (int)wxINT32_SWAP_ON_BE(dbuf[0]);
  899.     if ( comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 &&
  900.          comp != BI_BITFIELDS )
  901.     {
  902.         if (verbose)
  903.             wxLogError( _("DIB Header: Unknown encoding in file.") );
  904.         return FALSE;
  905.     }
  906.  
  907.     stream.Read(dbuf, 4 * 2);
  908.     int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
  909.     if (ncolors == 0)
  910.         ncolors = 1 << bpp;
  911.     /* some more sanity checks */
  912.     if (((comp == BI_RLE4) && (bpp != 4)) ||
  913.         ((comp == BI_RLE8) && (bpp != 8)) ||
  914.         ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
  915.     {
  916.         if (verbose)
  917.             wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") );
  918.         return FALSE;
  919.     }
  920.  
  921.     //read DIB; this is the BMP image or the XOR part of an icon image
  922.     if ( !DoLoadDib(image, width, height, bpp, ncolors, comp, offset, stream,
  923.                     verbose, IsBmp, TRUE) )
  924.     {
  925.         if (verbose)
  926.             wxLogError( _("Error in reading image DIB .") );
  927.         return FALSE;
  928.     }
  929.  
  930.     if ( !IsBmp )
  931.     {
  932.         //read Icon mask which is monochrome
  933.         //there is no palette, so we will create one
  934.         wxImage mask;
  935.         if ( !DoLoadDib(&mask, width, height, 1, 2, BI_RGB, offset, stream,
  936.                         verbose, IsBmp, FALSE) )
  937.         {
  938.             if (verbose)
  939.                 wxLogError( _("ICO: Error in reading mask DIB.") );
  940.             return FALSE;
  941.         }
  942.         image->SetMaskFromImage(mask, 255, 255, 255);
  943.  
  944.     }
  945.  
  946.     return TRUE;
  947. }
  948.  
  949. bool wxBMPHandler::LoadFile(wxImage *image, wxInputStream& stream,
  950.                             bool verbose, int WXUNUSED(index))
  951. {
  952.     // Read a single DIB fom the file:
  953.     return LoadDib(image, stream, verbose, TRUE/*isBmp*/);
  954. }
  955.  
  956. bool wxBMPHandler::DoCanRead(wxInputStream& stream)
  957. {
  958.     unsigned char hdr[2];
  959.  
  960.     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
  961.         return FALSE;
  962.  
  963.     // do we have the BMP file signature?
  964.     return hdr[0] == 'B' && hdr[1] == 'M';
  965. }
  966.  
  967.  
  968. #if wxUSE_ICO_CUR
  969. //-----------------------------------------------------------------------------
  970. // wxICOHandler
  971. //-----------------------------------------------------------------------------
  972.  
  973. IMPLEMENT_DYNAMIC_CLASS(wxICOHandler, wxBMPHandler)
  974.  
  975. struct ICONDIRENTRY
  976. {
  977.     wxUint8         bWidth;               // Width of the image
  978.     wxUint8         bHeight;              // Height of the image (times 2)
  979.     wxUint8         bColorCount;          // Number of colors in image (0 if >=8bpp)
  980.     wxUint8         bReserved;            // Reserved
  981.  
  982.     // these two are different in icons and cursors:
  983.                                           // icon           or  cursor
  984.     wxUint16        wPlanes;              // Color Planes   or  XHotSpot
  985.     wxUint16        wBitCount;            // Bits per pixel or  YHotSpot
  986.  
  987.     wxUint32        dwBytesInRes;         // how many bytes in this resource?
  988.     wxUint32        dwImageOffset;        // where in the file is this image
  989. };
  990.  
  991. struct ICONDIR
  992. {
  993.     wxUint16     idReserved;   // Reserved
  994.     wxUint16     idType;       // resource type (1 for icons, 2 for cursors)
  995.     wxUint16     idCount;      // how many images?
  996. };
  997.  
  998.  
  999. bool wxICOHandler::SaveFile(wxImage *image,
  1000.                             wxOutputStream& stream,
  1001.                             bool verbose)
  1002.  
  1003. {
  1004.     bool bResult = FALSE;
  1005.     //sanity check; icon must be less than 127 pixels high and 255 wide
  1006.     if ( image->GetHeight () > 127 )
  1007.     {
  1008.         if ( verbose )
  1009.             wxLogError(_("ICO: Image too tall for an icon."));
  1010.         return FALSE;
  1011.     }
  1012.     if ( image->GetWidth () > 255 )
  1013.     {
  1014.         if ( verbose )
  1015.             wxLogError(_("ICO: Image too wide for an icon."));
  1016.         return FALSE;
  1017.     }
  1018.  
  1019.     int images = 1; // only generate one image
  1020.  
  1021.     // VS: This is a hack of sort - since ICO and CUR files are almost
  1022.     //     identical, we have all the meat in wxICOHandler and check for
  1023.     //     the actual (handler) type when the code has to distinguish between
  1024.     //     the two formats
  1025.     int type = (this->GetType() == wxBITMAP_TYPE_CUR) ? 2 : 1;
  1026.  
  1027.     // write a header, (ICONDIR)
  1028.     // Calculate the header size
  1029.     wxUint32 offset = 3 * sizeof(wxUint16);
  1030.  
  1031.     ICONDIR IconDir;
  1032.     IconDir.idReserved = 0;
  1033.     IconDir.idType = wxUINT16_SWAP_ON_BE(type);
  1034.     IconDir.idCount = wxUINT16_SWAP_ON_BE(images);
  1035.     stream.Write(&IconDir.idReserved, sizeof(IconDir.idReserved));
  1036.     stream.Write(&IconDir.idType, sizeof(IconDir.idType));
  1037.     stream.Write(&IconDir.idCount, sizeof(IconDir.idCount));
  1038.     if ( !stream.IsOk() )
  1039.     {
  1040.         if ( verbose )
  1041.             wxLogError(_("ICO: Error writing the image file!"));
  1042.         return FALSE;
  1043.     }
  1044.  
  1045.     // for each iamage write a description ICONDIRENTRY:
  1046.     ICONDIRENTRY icondirentry;
  1047.     for (int i = 0; i < images; i++)
  1048.     {
  1049.         wxImage mask;
  1050.  
  1051.         if ( image->HasMask() )
  1052.         {
  1053.             // make another image with black/white:
  1054.             mask = image->ConvertToMono (image->GetMaskRed(), image->GetMaskGreen(), image->GetMaskBlue() );
  1055.  
  1056.             // now we need to change the masked regions to black:
  1057.             unsigned char r = image->GetMaskRed();
  1058.             unsigned char g = image->GetMaskGreen();
  1059.             unsigned char b = image->GetMaskBlue();
  1060.             if ( (r != 0) || (g != 0) || (b != 0) )
  1061.             {
  1062.                 // Go round and apply black to the masked bits:
  1063.                 int i, j;
  1064.                 for (i = 0; i < mask.GetWidth(); i++)
  1065.                 {
  1066.                     for (j = 0; j < mask.GetHeight(); j++)
  1067.                     {
  1068.                         if ((r == mask.GetRed(i, j)) &&
  1069.                             (g == mask.GetGreen(i, j))&&
  1070.                             (b == mask.GetBlue(i, j)) )
  1071.                                 image->SetRGB(i, j, 0, 0, 0 );
  1072.                     }
  1073.                 }
  1074.             }
  1075.         }
  1076.         else
  1077.         {
  1078.             // just make a black mask all over:
  1079.             mask = image->Copy();
  1080.             int i, j;
  1081.             for (i = 0; i < mask.GetWidth(); i++)
  1082.                 for (j = 0; j < mask.GetHeight(); j++)
  1083.                     mask.SetRGB(i, j, 0, 0, 0 );
  1084.         }
  1085.         // Set the formats for image and mask
  1086.         // (Windows never saves with more than 8 colors):
  1087.         image->SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP);
  1088.  
  1089.         // monochome bitmap:
  1090.         mask.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_1BPP_BW);
  1091.         bool IsBmp = FALSE;
  1092.         bool IsMask = FALSE;
  1093.  
  1094.         //calculate size and offset of image and mask
  1095.         wxCountingOutputStream cStream;
  1096.         bResult = SaveDib(image, cStream, verbose, IsBmp, IsMask);
  1097.         if ( !bResult )
  1098.         {
  1099.             if ( verbose )
  1100.                 wxLogError(_("ICO: Error writing the image file!"));
  1101.             return FALSE;
  1102.         }
  1103.         IsMask = TRUE;
  1104.  
  1105.         bResult = SaveDib(&mask, cStream, verbose, IsBmp, IsMask);
  1106.         if ( !bResult )
  1107.         {
  1108.             if ( verbose )
  1109.                 wxLogError(_("ICO: Error writing the image file!"));
  1110.             return FALSE;
  1111.         }
  1112.         wxUint32 Size = cStream.GetSize();
  1113.  
  1114.         // wxCountingOutputStream::Ok() always returns TRUE for now and this
  1115.         // "if" provokes VC++ warnings in optimized build
  1116. #if 0
  1117.         if ( !cStream.Ok() )
  1118.         {
  1119.             if ( verbose )
  1120.                 wxLogError(_("ICO: Error writing the image file!"));
  1121.             return FALSE;
  1122.         }
  1123. #endif // 0
  1124.  
  1125.         offset = offset + sizeof(ICONDIRENTRY);
  1126.  
  1127.         icondirentry.bWidth = image->GetWidth();
  1128.         icondirentry.bHeight = 2 * image->GetHeight();
  1129.         icondirentry.bColorCount = 0;
  1130.         icondirentry.bReserved = 0;
  1131.         icondirentry.wPlanes = wxUINT16_SWAP_ON_BE(1);
  1132.         icondirentry.wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP);
  1133.         if ( type == 2 /*CUR*/)
  1134.         {
  1135.             int hx = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ?
  1136.                          image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X) :
  1137.                          image->GetWidth() / 2;
  1138.             int hy = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ?
  1139.                          image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y) :
  1140.                          image->GetHeight() / 2;
  1141.  
  1142.             // actually write the values of the hot spot here:
  1143.             icondirentry.wPlanes = wxUINT16_SWAP_ON_BE((wxUint16)hx);
  1144.             icondirentry.wBitCount = wxUINT16_SWAP_ON_BE((wxUint16)hy);
  1145.         }
  1146.         icondirentry.dwBytesInRes = wxUINT32_SWAP_ON_BE(Size);
  1147.         icondirentry.dwImageOffset = wxUINT32_SWAP_ON_BE(offset);
  1148.  
  1149.         // increase size to allow for the data written:
  1150.         offset += Size;
  1151.  
  1152.         // write to stream:
  1153.         stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth));
  1154.         stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight));
  1155.         stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount));
  1156.         stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved));
  1157.         stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes));
  1158.         stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount));
  1159.         stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes));
  1160.         stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset));
  1161.         if ( !stream.IsOk() )
  1162.         {
  1163.             if ( verbose )
  1164.                 wxLogError(_("ICO: Error writing the image file!"));
  1165.             return FALSE;
  1166.         }
  1167.  
  1168.         // actually save it:
  1169.         IsMask = FALSE;
  1170.         bResult = SaveDib(image, stream, verbose, IsBmp, IsMask);
  1171.         if ( !bResult )
  1172.         {
  1173.             if ( verbose )
  1174.                 wxLogError(_("ICO: Error writing the image file!"));
  1175.             return FALSE;
  1176.         }
  1177.         IsMask = TRUE;
  1178.  
  1179.         bResult = SaveDib(&mask, stream, verbose, IsBmp, IsMask);
  1180.         if ( !bResult )
  1181.         {
  1182.             if ( verbose )
  1183.                 wxLogError(_("ICO: Error writing the image file!"));
  1184.             return FALSE;
  1185.         }
  1186.  
  1187.     } // end of for loop
  1188.  
  1189.     return TRUE;
  1190. }
  1191.  
  1192. bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream,
  1193.                             bool verbose, int index)
  1194. {
  1195.     stream.SeekI(0);
  1196.     return DoLoadFile(image, stream, verbose, index);
  1197. }
  1198.  
  1199. bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
  1200.                             bool WXUNUSED(verbose), int index)
  1201. {
  1202.     bool bResult = FALSE;
  1203.     bool IsBmp = FALSE;
  1204.  
  1205.     ICONDIR IconDir;
  1206.  
  1207.     off_t iPos = stream.TellI();
  1208.     stream.Read(&IconDir, sizeof(IconDir));
  1209.     wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
  1210.     // nType is 1 for Icons, 2 for Cursors:
  1211.     wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType);
  1212.  
  1213.     // loop round the icons and choose the best one:
  1214.     ICONDIRENTRY *pIconDirEntry = new ICONDIRENTRY[nIcons];
  1215.     ICONDIRENTRY *pCurrentEntry = pIconDirEntry;
  1216.     int wMax = 0;
  1217.     int colmax = 0;
  1218.     int iSel = wxNOT_FOUND;
  1219.  
  1220.     for (int i = 0; i < nIcons; i++ )
  1221.     {
  1222.         stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY));
  1223.         // bHeight and bColorCount are wxUint8
  1224.         if ( pCurrentEntry->bWidth >= wMax )
  1225.         {
  1226.             // see if we have more colors, ==0 indicates > 8bpp:
  1227.             if ( pCurrentEntry->bColorCount == 0 )
  1228.                 pCurrentEntry->bColorCount = 255;
  1229.             if ( pCurrentEntry->bColorCount >= colmax )
  1230.             {
  1231.                 iSel = i;
  1232.                 wMax = pCurrentEntry->bWidth;
  1233.                 colmax = pCurrentEntry->bColorCount;
  1234.             }
  1235.         }
  1236.         pCurrentEntry++;
  1237.     }
  1238.  
  1239.     if ( index != -1 )
  1240.     {
  1241.         // VS: Note that we *have* to run the loop above even if index != -1, because
  1242.         //     it reads ICONDIRENTRies.
  1243.         iSel = index;
  1244.     }
  1245.  
  1246.     if ( iSel == wxNOT_FOUND || iSel < 0 || iSel >= nIcons )
  1247.     {
  1248.         wxLogError(_("ICO: Invalid icon index."));
  1249.         bResult = FALSE;
  1250.     }
  1251.     else
  1252.     {
  1253.         // seek to selected icon:
  1254.         pCurrentEntry = pIconDirEntry + iSel;
  1255.         stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart);
  1256.         bResult = LoadDib(image, stream, TRUE, IsBmp);
  1257.         bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI);
  1258.         if ( bResult && bIsCursorType && nType == 2 )
  1259.         {
  1260.             // it is a cursor, so let's set the hotspot:
  1261.             image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, wxUINT16_SWAP_ON_BE(pCurrentEntry->wPlanes));
  1262.             image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount));
  1263.         }
  1264.     }
  1265.     delete[] pIconDirEntry;
  1266.     return bResult;
  1267. }
  1268.  
  1269. int wxICOHandler::GetImageCount(wxInputStream& stream)
  1270. {
  1271.     ICONDIR IconDir;
  1272.     off_t iPos = stream.TellI();
  1273.     stream.SeekI(0);
  1274.     stream.Read(&IconDir, sizeof(IconDir));
  1275.     wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
  1276.     stream.SeekI(iPos);
  1277.     return (int)nIcons;
  1278. }
  1279.  
  1280. bool wxICOHandler::DoCanRead(wxInputStream& stream)
  1281. {
  1282.     stream.SeekI(0);
  1283.     unsigned char hdr[4];
  1284.     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
  1285.         return FALSE;
  1286.  
  1287.     // hdr[2] is one for an icon and two for a cursor
  1288.     return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0';
  1289. }
  1290.  
  1291.  
  1292.  
  1293. //-----------------------------------------------------------------------------
  1294. // wxCURHandler
  1295. //-----------------------------------------------------------------------------
  1296.  
  1297. IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler)
  1298.  
  1299. bool wxCURHandler::DoCanRead(wxInputStream& stream)
  1300. {
  1301.     stream.SeekI(0);
  1302.     unsigned char hdr[4];
  1303.     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
  1304.         return FALSE;
  1305.  
  1306.     // hdr[2] is one for an icon and two for a cursor
  1307.     return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0';
  1308. }
  1309.  
  1310. //-----------------------------------------------------------------------------
  1311. // wxANIHandler
  1312. //-----------------------------------------------------------------------------
  1313.  
  1314. IMPLEMENT_DYNAMIC_CLASS(wxANIHandler, wxCURHandler)
  1315.  
  1316. bool wxANIHandler::LoadFile(wxImage *image, wxInputStream& stream,
  1317.                             bool verbose, int index)
  1318. {
  1319.     wxInt32 FCC1, FCC2;
  1320.     wxUint32 datalen;
  1321.  
  1322.     wxInt32 riff32;
  1323.     memcpy( &riff32, "RIFF", 4 );
  1324.     wxInt32 list32;
  1325.     memcpy( &list32, "LIST", 4 );
  1326.     wxInt32 ico32;
  1327.     memcpy( &ico32, "icon", 4 );
  1328.     int iIcon = 0;
  1329.  
  1330.     stream.SeekI(0);
  1331.     stream.Read(&FCC1, 4);
  1332.     if ( FCC1 != riff32 )
  1333.         return FALSE;
  1334.  
  1335.     // we have a riff file:
  1336.     while (stream.IsOk())
  1337.     {
  1338.         // we always have a data size
  1339.         stream.Read(&datalen, 4);
  1340.         datalen = wxINT32_SWAP_ON_BE(datalen) ;
  1341.         //data should be padded to make even number of bytes
  1342.         if (datalen % 2 == 1) datalen ++ ;
  1343.         //now either data or a FCC
  1344.         if ( (FCC1 == riff32) || (FCC1 == list32) )
  1345.         {
  1346.             stream.Read(&FCC2, 4);
  1347.         }
  1348.         else
  1349.         {
  1350.             if (FCC1 == ico32 && iIcon >= index)
  1351.             {
  1352.                 return DoLoadFile(image, stream, verbose, -1);
  1353.             }
  1354.             else
  1355.             {
  1356.                 stream.SeekI(stream.TellI() + datalen);
  1357.                 if ( FCC1 == ico32 )
  1358.                     iIcon ++;
  1359.             }
  1360.         }
  1361.  
  1362.         // try to read next data chunk:
  1363.         stream.Read(&FCC1, 4);
  1364.     }
  1365.     return FALSE;
  1366. }
  1367.  
  1368. bool wxANIHandler::DoCanRead(wxInputStream& stream)
  1369. {
  1370.     wxInt32 FCC1, FCC2;
  1371.     wxUint32 datalen ;
  1372.     
  1373.     wxInt32 riff32;
  1374.     memcpy( &riff32, "RIFF", 4 );
  1375.     wxInt32 list32;
  1376.     memcpy( &list32, "LIST", 4 );
  1377.     wxInt32 ico32;
  1378.     memcpy( &ico32, "icon", 4 ); 
  1379.     wxInt32 anih32;
  1380.     memcpy( &anih32, "anih", 4 );
  1381.     
  1382.     stream.SeekI(0);
  1383.     if ( !stream.Read(&FCC1, 4) )
  1384.         return FALSE;
  1385.  
  1386.     if ( FCC1 != riff32 )
  1387.         return FALSE;
  1388.  
  1389.     // we have a riff file:
  1390.     while ( stream.IsOk() )
  1391.     {
  1392.         if ( FCC1 == anih32 )
  1393.             return TRUE;
  1394.         // we always have a data size:
  1395.         stream.Read(&datalen, 4);
  1396.         datalen = wxINT32_SWAP_ON_BE(datalen) ;
  1397.         //data should be padded to make even number of bytes
  1398.         if (datalen % 2 == 1) datalen ++ ;
  1399.         // now either data or a FCC:
  1400.         if ( (FCC1 == riff32) || (FCC1 == list32) )
  1401.         {
  1402.             stream.Read(&FCC2, 4);
  1403.         }
  1404.         else
  1405.         {
  1406.             stream.SeekI(stream.TellI() + datalen);
  1407.         }
  1408.  
  1409.         // try to read next data chunk:
  1410.         if ( !stream.Read(&FCC1, 4) )
  1411.         {
  1412.             // reading failed -- either EOF or IO error, bail out anyhow
  1413.             return FALSE;
  1414.         }
  1415.     }
  1416.  
  1417.     return FALSE;
  1418. }
  1419.  
  1420. int wxANIHandler::GetImageCount(wxInputStream& stream)
  1421. {
  1422.     wxInt32 FCC1, FCC2;
  1423.     wxUint32 datalen ;
  1424.  
  1425.     wxInt32 riff32;
  1426.     memcpy( &riff32, "RIFF", 4 );
  1427.     wxInt32 list32;
  1428.     memcpy( &list32, "LIST", 4 );
  1429.     wxInt32 ico32;
  1430.     memcpy( &ico32, "icon", 4 );
  1431.     wxInt32 anih32;
  1432.     memcpy( &anih32, "anih", 4 );
  1433.     
  1434.     stream.SeekI(0);
  1435.     stream.Read(&FCC1, 4);
  1436.     if ( FCC1 != riff32 )
  1437.         return wxNOT_FOUND;
  1438.  
  1439.     // we have a riff file:
  1440.     while ( stream.IsOk() )
  1441.     {
  1442.         // we always have a data size:
  1443.         stream.Read(&datalen, 4);
  1444.         datalen = wxINT32_SWAP_ON_BE(datalen) ;
  1445.         //data should be padded to make even number of bytes
  1446.         if (datalen % 2 == 1) datalen ++ ;
  1447.         // now either data or a FCC:
  1448.         if ( (FCC1 == riff32) || (FCC1 == list32) )
  1449.         {
  1450.             stream.Read(&FCC2, 4);
  1451.         }
  1452.         else
  1453.         {
  1454.             if ( FCC1 == anih32 )
  1455.             {
  1456.                 wxUint32 *pData = new wxUint32[datalen/4];
  1457.                 stream.Read(pData, datalen);
  1458.                 int nIcons = wxINT32_SWAP_ON_BE(*(pData + 1));
  1459.                 delete[] pData;
  1460.                 return nIcons;
  1461.             }
  1462.             else
  1463.                 stream.SeekI(stream.TellI() + datalen);
  1464.         }
  1465.  
  1466.         // try to read next data chunk:
  1467.         stream.Read(&FCC1, 4);
  1468.     }
  1469.  
  1470.     return wxNOT_FOUND;
  1471. }
  1472.  
  1473. #endif // wxUSE_ICO_CUR
  1474.  
  1475. #endif // wxUSE_IMAGE && wxUSE_STREAMS
  1476.