+ }
+ }
+ 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(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP);
+
+ // monochome bitmap:
+ mask.SetOption(wxIMAGE_OPTION_BMP_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 writing the image file!"));
+ return FALSE;
+ }
+ IsMask = TRUE;
+
+ bResult = SaveDib(&mask, cStream, verbose, IsBmp, IsMask);
+ if ( !bResult )
+ {
+ if ( verbose )
+ wxLogError(_("ICO: Error writing the image file!"));
+ return FALSE;
+ }
+ wxUint32 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 writing the image file!"));
+ return FALSE;
+ }
+#endif // 0
+
+ offset = offset + sizeof(ICONDIRENTRY);
+
+ icondirentry.bWidth = image->GetWidth();
+ icondirentry.bHeight = 2 * image->GetHeight();
+ icondirentry.bColorCount = 0;
+ icondirentry.bReserved = 0;
+ icondirentry.wPlanes = wxUINT16_SWAP_ON_BE(1);
+ icondirentry.wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP);
+ if ( type == 2 /*CUR*/)
+ {
+ int hx = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ?
+ image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X) :
+ image->GetWidth() / 2;
+ int hy = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ?
+ image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y) :
+ image->GetHeight() / 2;
+
+ // actually write the values of the hot spot here:
+ icondirentry.wPlanes = wxUINT16_SWAP_ON_BE((wxUint16)hx);
+ icondirentry.wBitCount = wxUINT16_SWAP_ON_BE((wxUint16)hy);
+ }
+ icondirentry.dwBytesInRes = wxUINT32_SWAP_ON_BE(Size);
+ icondirentry.dwImageOffset = wxUINT32_SWAP_ON_BE(offset);
+
+ // increase size to allow for the data written:
+ offset += Size;
+
+ // write to stream:
+ stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth));
+ stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight));
+ stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount));
+ stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved));
+ stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes));
+ stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount));
+ stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes));
+ stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset));
+ if ( !stream.IsOk() )
+ {
+ if ( verbose )
+ wxLogError(_("ICO: Error writing the image file!"));
+ return FALSE;
+ }
+
+ // actually save it:
+ IsMask = FALSE;
+ bResult = SaveDib(image, stream, verbose, IsBmp, IsMask);
+ if ( !bResult )
+ {
+ if ( verbose )
+ wxLogError(_("ICO: Error writing the image file!"));
+ return FALSE;
+ }
+ IsMask = TRUE;
+
+ bResult = SaveDib(&mask, stream, verbose, IsBmp, IsMask);
+ if ( !bResult )
+ {
+ if ( verbose )
+ wxLogError(_("ICO: Error writing the image file!"));
+ return FALSE;
+ }
+
+ } // end of for loop
+
+ return TRUE;
+}
+
+bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream,
+ bool verbose, int index)
+{
+ stream.SeekI(0);
+ return DoLoadFile(image, stream, verbose, index);
+}
+
+bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
+ bool WXUNUSED(verbose), int index)
+{
+ bool bResult = FALSE;
+ bool IsBmp = FALSE;
+
+ ICONDIR IconDir;
+
+ off_t iPos = stream.TellI();
+ stream.Read(&IconDir, sizeof(IconDir));
+ wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
+ // nType is 1 for Icons, 2 for Cursors:
+ wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType);
+
+ // loop round the icons and choose the best one:
+ ICONDIRENTRY *pIconDirEntry = new ICONDIRENTRY[nIcons];
+ ICONDIRENTRY *pCurrentEntry = pIconDirEntry;
+ int wMax = 0;
+ int colmax = 0;
+ int iSel = wxNOT_FOUND;
+
+ for (int i = 0; i < nIcons; i++ )
+ {
+ stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY));
+ // bHeight and bColorCount are wxUint8
+ if ( pCurrentEntry->bWidth >= wMax )
+ {
+ // see if we have more colors, ==0 indicates > 8bpp:
+ if ( pCurrentEntry->bColorCount == 0 )
+ pCurrentEntry->bColorCount = 255;
+ if ( pCurrentEntry->bColorCount >= colmax )
+ {
+ iSel = i;
+ wMax = pCurrentEntry->bWidth;
+ colmax = pCurrentEntry->bColorCount;
+ }
+ }
+ pCurrentEntry++;
+ }
+
+ if ( index != -1 )
+ {
+ // VS: Note that we *have* to run the loop above even if index != -1, because
+ // it reads ICONDIRENTRies.
+ iSel = index;
+ }
+
+ if ( iSel == wxNOT_FOUND || iSel < 0 || iSel >= nIcons )
+ {
+ wxLogError(_("ICO: Invalid icon index."));
+ bResult = FALSE;
+ }
+ else
+ {
+ // seek to selected icon:
+ pCurrentEntry = pIconDirEntry + iSel;
+ stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart);
+ bResult = LoadDib(image, stream, TRUE, IsBmp);
+ bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI);
+ if ( bResult && bIsCursorType && nType == 2 )
+ {
+ // it is a cursor, so let's set the hotspot:
+ image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, wxUINT16_SWAP_ON_BE(pCurrentEntry->wPlanes));
+ image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount));
+ }
+ }
+ delete[] pIconDirEntry;
+ return bResult;
+}
+
+int wxICOHandler::GetImageCount(wxInputStream& stream)
+{
+ ICONDIR IconDir;
+ off_t iPos = stream.TellI();
+ stream.SeekI(0);
+ stream.Read(&IconDir, sizeof(IconDir));
+ wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
+ stream.SeekI(iPos);
+ return (int)nIcons;
+}
+
+bool wxICOHandler::DoCanRead(wxInputStream& stream)
+{
+ stream.SeekI(0);
+ unsigned char hdr[4];
+ if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
+ return FALSE;
+
+ // hdr[2] is one for an icon and two for a cursor
+ return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0';
+}
+
+#endif // wxUSE_STREAMS
+
+
+//-----------------------------------------------------------------------------
+// wxCURHandler
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler)
+
+#if wxUSE_STREAMS
+
+bool wxCURHandler::DoCanRead(wxInputStream& stream)
+{
+ stream.SeekI(0);
+ unsigned char hdr[4];
+ if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
+ return FALSE;
+
+ // hdr[2] is one for an icon and two for a cursor
+ return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0';
+}
+
+#endif // wxUSE_STREAMS
+
+//-----------------------------------------------------------------------------
+// wxANIHandler
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxANIHandler, wxCURHandler)
+
+#if wxUSE_STREAMS
+
+bool wxANIHandler::LoadFile(wxImage *image, wxInputStream& stream,
+ bool verbose, int index)
+{
+ wxInt32 FCC1, FCC2;
+ wxUint32 datalen;
+
+ wxInt32 riff32;
+ memcpy( &riff32, "RIFF", 4 );
+ wxInt32 list32;
+ memcpy( &list32, "LIST", 4 );
+ wxInt32 ico32;
+ memcpy( &ico32, "icon", 4 );
+ int iIcon = 0;
+
+ stream.SeekI(0);
+ stream.Read(&FCC1, 4);
+ if ( FCC1 != riff32 )
+ return FALSE;
+
+ // we have a riff file:
+ while (stream.IsOk())
+ {
+ // we always have a data size
+ stream.Read(&datalen, 4);
+ datalen = wxINT32_SWAP_ON_BE(datalen) ;
+ //data should be padded to make even number of bytes
+ if (datalen % 2 == 1) datalen ++ ;
+ //now either data or a FCC
+ if ( (FCC1 == riff32) || (FCC1 == list32) )
+ {
+ stream.Read(&FCC2, 4);
+ }
+ else
+ {
+ if (FCC1 == ico32 && iIcon >= index)
+ {
+ return DoLoadFile(image, stream, verbose, -1);
+ }
+ else
+ {
+ stream.SeekI(stream.TellI() + datalen);
+ if ( FCC1 == ico32 )
+ iIcon ++;
+ }
+ }
+
+ // try to read next data chunk:
+ stream.Read(&FCC1, 4);
+ }
+ return FALSE;
+}
+
+bool wxANIHandler::DoCanRead(wxInputStream& stream)
+{
+ wxInt32 FCC1, FCC2;
+ wxUint32 datalen ;
+
+ wxInt32 riff32;
+ memcpy( &riff32, "RIFF", 4 );
+ wxInt32 list32;
+ memcpy( &list32, "LIST", 4 );
+ wxInt32 ico32;
+ memcpy( &ico32, "icon", 4 );
+ wxInt32 anih32;
+ memcpy( &anih32, "anih", 4 );
+
+ stream.SeekI(0);
+ if ( !stream.Read(&FCC1, 4) )
+ return FALSE;
+
+ if ( FCC1 != riff32 )
+ return FALSE;
+
+ // we have a riff file:
+ while ( stream.IsOk() )
+ {
+ if ( FCC1 == anih32 )
+ return TRUE;
+ // we always have a data size:
+ stream.Read(&datalen, 4);
+ datalen = wxINT32_SWAP_ON_BE(datalen) ;
+ //data should be padded to make even number of bytes
+ if (datalen % 2 == 1) datalen ++ ;
+ // now either data or a FCC:
+ if ( (FCC1 == riff32) || (FCC1 == list32) )
+ {
+ stream.Read(&FCC2, 4);
+ }
+ else
+ {
+ stream.SeekI(stream.TellI() + datalen);
+ }
+
+ // try to read next data chunk:
+ if ( !stream.Read(&FCC1, 4) )
+ {
+ // reading failed -- either EOF or IO error, bail out anyhow
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+int wxANIHandler::GetImageCount(wxInputStream& stream)
+{
+ wxInt32 FCC1, FCC2;
+ wxUint32 datalen ;
+
+ wxInt32 riff32;
+ memcpy( &riff32, "RIFF", 4 );
+ wxInt32 list32;
+ memcpy( &list32, "LIST", 4 );
+ wxInt32 ico32;
+ memcpy( &ico32, "icon", 4 );
+ wxInt32 anih32;
+ memcpy( &anih32, "anih", 4 );
+
+ stream.SeekI(0);
+ stream.Read(&FCC1, 4);
+ if ( FCC1 != riff32 )
+ return wxNOT_FOUND;
+
+ // we have a riff file:
+ while ( stream.IsOk() )
+ {
+ // we always have a data size:
+ stream.Read(&datalen, 4);
+ datalen = wxINT32_SWAP_ON_BE(datalen) ;
+ //data should be padded to make even number of bytes
+ if (datalen % 2 == 1) datalen ++ ;
+ // now either data or a FCC:
+ if ( (FCC1 == riff32) || (FCC1 == list32) )
+ {
+ stream.Read(&FCC2, 4);
+ }
+ else
+ {
+ if ( FCC1 == anih32 )
+ {
+ wxUint32 *pData = new wxUint32[datalen/4];
+ stream.Read(pData, datalen);
+ int nIcons = wxINT32_SWAP_ON_BE(*(pData + 1));
+ delete[] pData;
+ return nIcons;
+ }
+ else
+ stream.SeekI(stream.TellI() + datalen);
+ }
+
+ // try to read next data chunk:
+ stream.Read(&FCC1, 4);
+ }
+
+ return wxNOT_FOUND;