Applied Chris' patch for support for ICO loading.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12473 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robert Roebling
2001-11-18 09:43:06 +00:00
parent 990578f892
commit 52b64b0a78
5 changed files with 385 additions and 88 deletions

View File

@@ -41,22 +41,58 @@ enum
class WXDLLEXPORT wxBMPHandler : public wxImageHandler class WXDLLEXPORT wxBMPHandler : public wxImageHandler
{ {
public: public:
wxBMPHandler() wxBMPHandler()
{ {
m_name = _T("BMP file"); m_name = _T("BMP file");
m_extension = _T("bmp"); m_extension = _T("bmp");
m_type = wxBITMAP_TYPE_BMP; m_type = wxBITMAP_TYPE_BMP;
m_mime = _T("image/bmp"); m_mime = _T("image/bmp");
}; };
#if wxUSE_STREAMS #if wxUSE_STREAMS
virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=TRUE );
virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=TRUE );
virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=TRUE, int index=0 ); virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=TRUE, int index=0 );
virtual bool DoCanRead( wxInputStream& stream ); virtual bool DoCanRead( wxInputStream& stream );
protected:
bool DoLoadDib (wxImage * image, int width, int height, int bpp, int ncolors, int comp,
off_t bmpOffset, wxInputStream& stream,
bool verbose, bool IsBmp, bool hasPalette ) ;
bool LoadDib( wxImage *image, wxInputStream& stream, bool verbose, bool IsBmp ) ;
#endif // wxUSE_STREAMS #endif // wxUSE_STREAMS
DECLARE_DYNAMIC_CLASS(wxBMPHandler) private:
DECLARE_DYNAMIC_CLASS(wxBMPHandler)
};
// ----------------------------------------------------------------------------
// wxICOHandler
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxICOHandler : public wxBMPHandler
{
public:
wxICOHandler()
{
m_name = _T("ICO file");
m_extension = _T("ico");
m_type = wxBITMAP_TYPE_ICO;
m_mime = _T("image/icon");
};
#if wxUSE_STREAMS
virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=TRUE );
virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=TRUE, int index=0 );
virtual bool DoCanRead( wxInputStream& stream );
#endif // wxUSE_STREAMS
private:
DECLARE_DYNAMIC_CLASS(wxBMPHandler)
}; };

View File

@@ -151,6 +151,10 @@ public:
unsigned char GetGreen( int x, int y ) const; unsigned char GetGreen( int x, int y ) const;
unsigned char GetBlue( int x, int y ) const; unsigned char GetBlue( int x, int y ) const;
// used to manipulate the icons while extracting from .ico files
bool GetUnusedColour( unsigned char *r, unsigned char *g, unsigned char *b );
bool ApplyMask( const wxImage & mask );
static bool CanRead( const wxString& name ); static bool CanRead( const wxString& name );
virtual bool LoadFile( const wxString& name, long type = wxBITMAP_TYPE_ANY ); virtual bool LoadFile( const wxString& name, long type = wxBITMAP_TYPE_ANY );
virtual bool LoadFile( const wxString& name, const wxString& mimetype ); virtual bool LoadFile( const wxString& name, const wxString& mimetype );

View File

@@ -55,6 +55,7 @@ void wxInitAllImageHandlers()
#if wxUSE_XPM #if wxUSE_XPM
wxImage::AddHandler( new wxXPMHandler ); wxImage::AddHandler( new wxXPMHandler );
#endif #endif
wxImage::AddHandler( new wxICOHandler );
} }
#endif // wxUSE_IMAGE #endif // wxUSE_IMAGE

View File

@@ -409,111 +409,74 @@ bool wxBMPHandler::SaveFile(wxImage *image,
#define poffset (line * width * 3 + column * 3) #define poffset (line * width * 3 + column * 3)
bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
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 wxBMPHandler::DoLoadDib (wxImage * image, int width, int height, int bpp, int ncolors, int comp,
off_t bmpOffset, wxInputStream& stream,
bool verbose, bool IsBmp, bool hasPalette )
{
wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0;
int rshift = 0, gshift = 0, bshift = 0; int rshift = 0, gshift = 0, bshift = 0;
wxInt32 dbuf[4];
wxInt8 bbuf[4];
wxUint8 aByte; wxUint8 aByte;
wxUint16 aWord; wxUint16 aWord;
wxInt32 dbuf[4];
wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0;
wxInt8 bbuf[4]; // allocate space for palette if needed
struct _cmap { struct _cmap
{
unsigned char r, g, b; unsigned char r, g, b;
} *cmap = NULL;
off_t start_offset = stream.TellI();
if (start_offset == wxInvalidOffset) start_offset = 0;
image->Destroy();
/*
* Read the BMP header
*/
stream.Read( bbuf, 2 );
stream.Read( dbuf, 4 * 4 );
#if 0 // unused
wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
#endif
wxInt32 offset = wxINT32_SWAP_ON_BE( dbuf[2] );
stream.Read(dbuf, 4 * 2);
int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
if (width > 32767)
{
if (verbose)
wxLogError( _("BMP: Image width > 32767 pixels for file.") );
return FALSE;
}
if (height > 32767)
{
if (verbose)
wxLogError( _("BMP: Image height > 32767 pixels for file.") );
return FALSE;
} }
*cmap = NULL;
stream.Read( &aWord, 2 );
/*
TODO
int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
*/
stream.Read( &aWord, 2 );
int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
{
if (verbose)
wxLogError( _("BMP: Unknown bitdepth in file.") );
return FALSE;
}
stream.Read( dbuf, 4 * 4 );
int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
{
if (verbose)
wxLogError( _("BMP: Unknown encoding in file.") );
return FALSE;
}
stream.Read( dbuf, 4 * 2 );
int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
if (ncolors == 0)
ncolors = 1 << bpp;
/* some more sanity checks */
if (((comp == BI_RLE4) && (bpp != 4)) ||
((comp == BI_RLE8) && (bpp != 8)) ||
((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
{
if (verbose)
wxLogError( _("BMP: Encoding doesn't match bitdepth.") );
return FALSE;
}
if (bpp < 16) if (bpp < 16)
{ {
cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors); cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
if (!cmap) if (!cmap)
{ {
if (verbose) if (verbose)
wxLogError( _("BMP: Couldn't allocate memory.") ); wxLogError( _("Loading DIB : Couldn't allocate memory.") );
return FALSE; return FALSE;
} }
} }
else else
cmap = NULL; cmap = NULL;
// destroy existing here instead of
image->Destroy();
image->Create( width, height ); image->Create( width, height );
unsigned char *ptr = image->GetData(); unsigned char *ptr = image->GetData();
if (!ptr) if (!ptr)
{ {
if (verbose) if (verbose)
wxLogError( _("BMP: Couldn't allocate memory.") ); wxLogError( _("Loading DIB : Couldn't allocate memory.") );
if (cmap) if (cmap)
free(cmap); free(cmap);
return FALSE; return FALSE;
} }
/* /*
* Reading the palette, if it exists. * Reading the palette, if it exists.
*/ */
@@ -524,6 +487,8 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose
unsigned char* b = new unsigned char[ncolors]; unsigned char* b = new unsigned char[ncolors];
for (int j = 0; j < ncolors; j++) for (int j = 0; j < ncolors; j++)
{ {
if (hasPalette)
{
stream.Read( bbuf, 4 ); stream.Read( bbuf, 4 );
cmap[j].b = bbuf[0]; cmap[j].b = bbuf[0];
cmap[j].g = bbuf[1]; cmap[j].g = bbuf[1];
@@ -533,6 +498,14 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose
g[j] = cmap[j].g; g[j] = cmap[j].g;
b[j] = cmap[j].b; b[j] = cmap[j].b;
} }
else
{
//used in reading .ico file mask
r[j] = cmap[j].r = j * 255;
g[j] = cmap[j].g = j * 255;
b[j] = cmap[j].b = j * 255;
}
}
#if wxUSE_PALETTE #if wxUSE_PALETTE
// Set the palette for the wxImage // Set the palette for the wxImage
@@ -586,7 +559,8 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose
/* /*
* Reading the image data * Reading the image data
*/ */
stream.SeekI( start_offset + offset ); if ( IsBmp ) stream.SeekI( bmpOffset ); // else icon, just carry on
unsigned char *data = ptr; unsigned char *data = ptr;
/* set the whole image to the background color */ /* set the whole image to the background color */
@@ -633,7 +607,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose
if (comp == BI_RLE4) if (comp == BI_RLE4)
{ {
if (verbose) if (verbose)
wxLogError( _("BMP: Cannot deal with 4bit encoded yet.") ); wxLogError( _("DIB Header: Cannot deal with 4bit encoded yet.") );
image->Destroy(); image->Destroy();
free(cmap); free(cmap);
return FALSE; return FALSE;
@@ -768,9 +742,188 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose
image->SetMask( FALSE ); image->SetMask( FALSE );
return stream.IsOk();
}
bool wxBMPHandler::LoadDib( wxImage *image, wxInputStream& stream, bool verbose, bool IsBmp )
{
wxUint8 aByte;
wxUint16 aWord;
wxInt32 dbuf[4];
wxInt8 bbuf[4];
off_t offset;
offset = 0; // keep gcc quiet
if ( IsBmp )
{
// read the header off the .BMP format file
offset = stream.TellI();
if (offset == wxInvalidOffset) offset = 0;
stream.Read( bbuf, 2 );
stream.Read( dbuf, 16 );
}
else
{
stream.Read( dbuf, 4 );
}
#if 0 // unused
wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
#endif
offset = offset + wxINT32_SWAP_ON_BE( dbuf[2] );
stream.Read(dbuf, 4 * 2);
int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
if ( !IsBmp ) height = height / 2; // for icons divide by 2
if (width > 32767)
{
if (verbose)
wxLogError( _("DIB Header: Image width > 32767 pixels for file.") );
return FALSE;
}
if (height > 32767)
{
if (verbose)
wxLogError( _("DIB Header: Image height > 32767 pixels for file.") );
return FALSE;
}
stream.Read( &aWord, 2 );
/*
TODO
int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
*/
stream.Read( &aWord, 2 );
int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
{
if (verbose)
wxLogError( _("DIB Header: Unknown bitdepth in file.") );
return FALSE;
}
stream.Read( dbuf, 4 * 4 );
int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
{
if (verbose)
wxLogError( _("DIB Header: Unknown encoding in file.") );
return FALSE;
}
stream.Read( dbuf, 4 * 2 );
int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
if (ncolors == 0)
ncolors = 1 << bpp;
/* some more sanity checks */
if (((comp == BI_RLE4) && (bpp != 4)) ||
((comp == BI_RLE8) && (bpp != 8)) ||
((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
{
if (verbose)
wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") );
return FALSE;
}
//read DIB; this is the BMP image or the XOR part of an icon image
if (!DoLoadDib (image, width, height, bpp, ncolors, comp, offset, stream,
verbose, IsBmp, TRUE ) )
{
if (verbose)
wxLogError( _("Error in reading image DIB .") );
return FALSE;
}
if ( !IsBmp )
{
//read Icon mask which is monochrome
//there is no palette, so we will create one
wxImage mask ;
if (!DoLoadDib (&mask, width, height, 1, 2, BI_RGB, offset, stream,
verbose, IsBmp, FALSE ) )
{
if (verbose)
wxLogError( _("ICO: Error in reading mask DIB.") );
return FALSE;
}
image -> ApplyMask ( &mask );
}
return TRUE; return TRUE;
} }
bool wxBMPHandler::LoadFile ( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
{
bool IsBmp = TRUE;
//Read a single DIB fom the file
return LoadDib ( image, stream, verbose, IsBmp ) ;
}
bool wxICOHandler::LoadFile ( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
{
bool bResult = FALSE ;
bool IsBmp = FALSE;
ICONDIR m_IconDir ;
stream.Read (&m_IconDir, sizeof(m_IconDir));
wxUint16 nIcons = wxUINT16_SWAP_ON_BE ( m_IconDir.idCount ) ;
//loop round the icons and choose the best one
ICONDIRENTRY * pIconDirEntry = new ICONDIRENTRY [nIcons];
ICONDIRENTRY * pCurrentEntry = pIconDirEntry ;
int i ;
int wMax = 0 ;
int colmax = 0 ;
int iSel = wxNOT_FOUND ;
for (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 (iSel == wxNOT_FOUND)
{
bResult = FALSE;
}
else
{
//seek to selected icon
pCurrentEntry = pIconDirEntry + iSel ;
stream.SeekI (wxUINT32_SWAP_ON_BE ( pCurrentEntry -> dwImageOffset ), wxFromStart ) ;
bResult = LoadDib ( image, stream, TRUE, IsBmp );
}
delete [] pIconDirEntry ;
return bResult
;
}
bool wxICOHandler::SaveFile(wxImage *image,
wxOutputStream& stream,
bool verbose)
{
return FALSE ;
}
bool wxBMPHandler::DoCanRead( wxInputStream& stream ) bool wxBMPHandler::DoCanRead( wxInputStream& stream )
{ {
unsigned char hdr[2]; unsigned char hdr[2];
@@ -780,6 +933,15 @@ bool wxBMPHandler::DoCanRead( wxInputStream& stream )
return (hdr[0] == 'B' && hdr[1] == 'M'); return (hdr[0] == 'B' && hdr[1] == 'M');
} }
bool wxICOHandler::DoCanRead( wxInputStream& stream )
{
unsigned char hdr[4];
stream.Read(hdr, 4);
stream.SeekI(-4, wxFromCurrent);
return (hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0');
}
#endif // wxUSE_STREAMS #endif // wxUSE_STREAMS
#endif // wxUSE_IMAGE #endif // wxUSE_IMAGE

View File

@@ -720,6 +720,100 @@ int wxImage::GetHeight() const
return M_IMGDATA->m_height; return M_IMGDATA->m_height;
} }
bool wxImage::GetUnusedColour ( unsigned char * r, unsigned char * g, unsigned char * b )
{
wxHashTable hTable;
unsigned long key;
ComputeHistogram( hTable );
// start with blackest color and work to lightest
// 0,0,0 is quite likely to be a used color
unsigned char r2 = 1;
unsigned char g2 = 0;
unsigned char b2 = 0;
key = (r2 << 16) | (g2 << 8) | b2;
while ( (wxHNode *) hTable.Get(key) )
{
// color already used
r2 ++ ;
if ( r2 >= 255 )
{
r2 = 0;
g2 ++ ;
if ( g2 >= 255 )
{
g2 = 0 ;
b2 ++ ;
if ( b2 >= 255 )
{
wxLogError( _("GetUnusedColour:: No Unused Color in image ") );
return FALSE;
}
}
}
key = (r2 << 16) | (g2 << 8) | b2;
}
return TRUE;
}
bool wxImage::ApplyMask ( const wxImage & mask )
{
// what to do if we already have a mask ??
if (M_IMGDATA->m_hasMask || mask.HasMask() )
{
wxLogError( _("Image already masked") );
return FALSE;
}
// check that the images are the same size
if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) )
{
wxLogError( _("Image and Mask have different sizes") );
return FALSE;
}
// find unused colour
unsigned char r,g,b ;
if (!GetUnusedColour (&r, &g, &b))
{
wxLogError( _("No Unused Color in image being masked") );
return FALSE ;
}
char unsigned *imgdata = GetData();
char unsigned *maskdata = mask.GetData();
const int w = GetWidth();
const int h = GetHeight();
for (int j = 0; j < h; j++)
for (int i = 0; i < w; i++)
{
if ((maskdata[0] > 128) && (maskdata[1] > 128) && (maskdata[2] > 128 ))
{
imgdata[0] = r;
imgdata[1] = g;
imgdata[2] = b;
}
imgdata += 3;
maskdata += 3;
}
M_IMGDATA->m_maskRed = r;
M_IMGDATA->m_maskGreen = g;
M_IMGDATA->m_maskBlue = b;
M_IMGDATA->m_hasMask = TRUE;
return TRUE;
}
#if wxUSE_PALETTE #if wxUSE_PALETTE
// Palette functions // Palette functions