+#ifndef BI_RGB
+#define BI_RGB 0
+#define BI_RLE8 1
+#define BI_RLE4 2
+#endif
+
+#ifndef BI_BITFIELDS
+#define BI_BITFIELDS 3
+#endif
+
+#define poffset (line * width * 3 + column * 3)
+
+
+
+struct ICONDIRENTRY
+ {
+ wxUint8 bWidth; // Width of the image
+ wxUint8 bHeight; // Height of the image (times 2)
+ wxUint8 bColorCount; // Number of colors in image (0 if >=8bpp)
+ wxUint8 bReserved; // Reserved
+ wxUint16 wPlanes; // Color Planes
+ wxUint16 wBitCount; // Bits per pixel
+ wxUint32 dwBytesInRes; // how many bytes in this resource?
+ wxUint32 dwImageOffset; // where in the file is this image
+} ;
+
+
+struct ICONDIR
+{
+ wxUint16 idReserved; // Reserved
+ wxUint16 idType; // resource type (1 for icons)
+ wxUint16 idCount; // how many images?
+} ;
+
+bool wxICOHandler::SaveFile(wxImage *image,
+ wxOutputStream& stream,
+ bool verbose)
+
+{
+ bool bResult = FALSE ;
+ //sanity check; icon must be less than 127 pixels high and 255 wide
+ if (image -> GetHeight () > 127 )
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error Image too tall for an icon.") );
+ return FALSE;
+ }
+ if (image -> GetWidth () > 255 )
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error Image too wide for an icon.") );
+ return FALSE;
+ }
+
+ // only generate one image
+ int m_images = 1 ;
+
+ // write a header, (ICONDIR)
+ // Calculate the header size
+ wxUint32 m_offset = 3 * sizeof(wxUint16);
+
+ ICONDIR m_IconDir ;
+ m_IconDir.idReserved = 0 ;
+ m_IconDir.idType = wxUINT16_SWAP_ON_BE (1);
+ m_IconDir.idCount = wxUINT16_SWAP_ON_BE (m_images);
+ stream.Write(&m_IconDir.idReserved, sizeof(m_IconDir.idReserved));
+ stream.Write(&m_IconDir.idType, sizeof(m_IconDir.idType));
+ stream.Write(&m_IconDir.idCount, sizeof(m_IconDir.idCount));
+ if ( !stream.IsOk () )
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error writing ICONDIR header.") );
+ return FALSE;
+ }
+
+ // for each iamage write a description ICONDIRENTRY
+ ICONDIRENTRY m_icondirentry ;
+ int i ;
+ for ( i = 0; i < m_images; i++ )
+ {
+ wxImage mask ;
+ if (image->HasMask())
+ {
+ //make another image with black/white
+ mask = image -> ConvertToMono (image->GetMaskRed(), image->GetMaskGreen(), image->GetMaskBlue() );
+ //now we need to change the masked regions to black
+ unsigned char r = image -> GetMaskRed() ;
+ unsigned char g = image -> GetMaskGreen() ;
+ unsigned char b = image -> GetMaskBlue() ;
+ if ((r != 0) || (g != 0) || (b != 0) )
+ {
+ //Go round and apply black to the masked bits
+ int i,j;
+ for (i=0; i < mask.GetWidth(); i++)
+ for (j=0; j < mask.GetHeight(); j++)
+ {
+ if ((r == mask.GetRed(i, j)) &&
+ (g == mask.GetGreen(i, j) ) &&
+ (b == mask.GetBlue(i, j)) )
+ image -> SetRGB ( i, j, 0, 0, 0 );
+ }
+
+ }
+ }
+ else
+ {
+ // just make a black mask all over
+ mask = image -> Copy ();
+ int i,j;
+ for (i=0; i < mask.GetWidth(); i++)
+ for (j=0; j < mask.GetHeight(); j++)
+ mask.SetRGB ( i, j, 0, 0, 0 );
+ }
+ //Set the formats for image and mask
+ // windows never saves with more than 8 colors
+ image -> SetOption (wxBMP_FORMAT, wxBMP_8BPP);
+ // monochome bitmap
+ mask . SetOption (wxBMP_FORMAT, wxBMP_1BPP_BW);
+ bool IsBmp = FALSE ;
+ bool IsMask = FALSE ;
+
+ //calculate size and offset of image and mask
+ wxCountingOutputStream cStream ;
+ bResult = SaveDib ( image, cStream, verbose, IsBmp, IsMask ) ;
+ if (!bResult)
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error calculating size of XOR DIB .") );
+ return FALSE;
+ }
+ IsMask = TRUE ;
+ bResult = SaveDib ( &mask, cStream, verbose, IsBmp, IsMask ) ;
+ if (!bResult)
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error calculating size of Mask DIB .") );
+ return FALSE;
+ }
+ wxUint32 m_Size = cStream.GetSize();
+
+ // wxCountingOutputStream::Ok() always returns TRUE for now and this
+ // "if" provokes VC++ warnings in optimized build
+#if 0
+ if (!cStream.Ok())
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error calculating size of DIB .") );
+ return FALSE;
+ }
+#endif // 0
+
+ m_offset = m_offset + sizeof(ICONDIRENTRY) ;
+
+ m_icondirentry. bWidth = image -> GetWidth () ;
+ m_icondirentry. bHeight = 2 * image -> GetHeight () ;
+ m_icondirentry. bColorCount = 0 ;
+ m_icondirentry. bReserved = 0 ;
+ m_icondirentry. wPlanes = wxUINT16_SWAP_ON_BE(1);
+ m_icondirentry. wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP) ;
+ m_icondirentry. dwBytesInRes = wxUINT32_SWAP_ON_BE(m_Size);
+ m_icondirentry. dwImageOffset = wxUINT32_SWAP_ON_BE(m_offset);
+
+ //increase size to allow for the data wriitten
+ m_offset = m_offset + m_Size ;
+
+ //write to stream
+ stream.Write(&m_icondirentry. bWidth, sizeof(m_icondirentry. bWidth) );
+ stream.Write(&m_icondirentry. bHeight, sizeof(m_icondirentry. bHeight) );
+ stream.Write(&m_icondirentry. bColorCount, sizeof(m_icondirentry. bColorCount) );
+ stream.Write(&m_icondirentry. bReserved, sizeof(m_icondirentry. bReserved) );
+ stream.Write(&m_icondirentry. wPlanes, sizeof(m_icondirentry. wPlanes) );
+ stream.Write(&m_icondirentry. wBitCount, sizeof(m_icondirentry. wBitCount) );
+ stream.Write(&m_icondirentry. dwBytesInRes, sizeof(m_icondirentry. dwBytesInRes) );
+ stream.Write(&m_icondirentry. dwImageOffset, sizeof(m_icondirentry. dwImageOffset) );
+ if ( !stream.IsOk () )
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error writing ICONDIRENTRY header.") );
+ return FALSE;
+ }
+ //actually save it
+ IsMask = FALSE ;
+ bResult = SaveDib ( image, stream, verbose, IsBmp, IsMask ) ;
+ if (!bResult)
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error writing XOR DIB .") );
+ return FALSE;
+ }
+ IsMask = TRUE ;
+ bResult = SaveDib ( &mask, stream, verbose, IsBmp, IsMask ) ;
+ if (!bResult)
+ {
+ if (verbose)
+ wxLogError( _("ICO: Error writing Mask DIB .") );
+ return FALSE;
+ }
+
+ } // end of for loop
+ return TRUE ;
+}
+
+