second halt of Chris' wxImage ICO patch

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12733 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík 2001-11-27 18:14:09 +00:00
parent 4f41713093
commit 37b83ca639
4 changed files with 296 additions and 45 deletions

View File

@ -81,6 +81,7 @@ All (GUI):
- wxDirSelector() added (Paul A. Thiessen)
- wxGrid cell editing veto support (Roger Gammans)
- wxListCtrl ITEM_FOCUSED event added
- support for ICO files in wxImage added (Chris Elliott)
wxMSW:

View File

@ -32,6 +32,7 @@ handler with \helpref{wxImage::AddHandler}{wximageaddhandler} or
\twocolitem{\indexit{wxPNMHandler}}{For loading and saving (see below).}
\twocolitem{\indexit{wxTIFFHandler}}{For loading and saving.}
\twocolitem{\indexit{wxXPMHandler}}{For loading and saving.}
\twocolitem{\indexit{wxICOHandler}}{For loading and saving.}
\end{twocollist}
When saving in PCX format, {\bf wxPCXHandler} will count the number of
@ -118,6 +119,7 @@ Loads an image from an input stream.
\twocolitem{\indexit{wxBITMAP\_TYPE\_PNM}}{Load a PNM bitmap file.}
\twocolitem{\indexit{wxBITMAP\_TYPE\_TIF}}{Load a TIFF bitmap file.}
\twocolitem{\indexit{wxBITMAP\_TYPE\_XPM}}{Load a XPM bitmap file.}
\twocolitem{\indexit{wxBITMAP\_TYPE\_ICO}}{Load a ICO Icon file.}
\twocolitem{\indexit{wxBITMAP\_TYPE\_ANY}}{Will try to autodetect the format.}
\end{twocollist}}
@ -229,6 +231,30 @@ TRUE if the call succeeded, FALSE otherwise.
Destroys the image data.
\membersection{wxImage::FindFirstUnusedColour}\label{wximagefindfirstunusedcolour}
\func{bool}{FindFirstUnusedColour}{\param{unsigned char *}{ r}, \param{unsigned char *}{ g}, \param{unsigned char *}{ b}, \param{unsigned char}{ startR = 1}, \param{unsigned char}{ startG = 0}, \param{unsigned char}{ startB = 0}}
\wxheading{Parameters}
\docparam{r,g,b}{Pointers to variables to save the colour.}
\docparam{startR,startG,startB}{Initial values of the colour. Returned colour
will have RGB values equal to or greater than these.}
Finds the first colour that is never used in the image. The search begins at
given initial colour and continues by increasing R, G and B components (in this
order) by 1 until an unused colour is found or the colour space exhausted.
\wxheading{Return value}
Returns FALSE if there is no unused colour left, TRUE on success.
\wxheading{Notes}
Note that this method involves computing the histogram, which is
computationally intensive operation.
\membersection{wxImage::FindHandler}
\func{static wxImageHandler*}{FindHandler}{\param{const wxString\& }{name}}
@ -455,6 +481,7 @@ Loads an image from an input stream.
\twocolitem{{\bf wxBITMAP\_TYPE\_PNM}}{Load a PNM image file.}
\twocolitem{{\bf wxBITMAP\_TYPE\_TIF}}{Load a TIFF image file.}
\twocolitem{{\bf wxBITMAP\_TYPE\_XPM}}{Load a XPM image file.}
\twocolitem{{\bf wxBITMAP\_TYPE\_ICO}}{Load a ICO icon file.}
\twocolitem{{\bf wxBITMAP\_TYPE\_ANY}}{Will try to autodetect the format.}
\end{twocollist}}
@ -464,6 +491,8 @@ Loads an image from an input stream.
Depending on how wxWindows has been configured, not all formats may be available.
wxBITMAP\_TYPE\_ICO will laod the largest image found, with the most colours
\wxheading{Return value}
TRUE if the operation succeeded, FALSE otherwise.
@ -543,6 +572,7 @@ Saves a image in the given stream.
\twocolitem{{\bf wxBITMAP\_TYPE\_PNM}}{Save a PNM image file (as raw RGB always).}
\twocolitem{{\bf wxBITMAP\_TYPE\_TIFF}}{Save a TIFF image file.}
\twocolitem{{\bf wxBITMAP\_TYPE\_XPM}}{Save a XPM image file.}
\twocolitem{{\bf wxBITMAP\_TYPE\_ICO}}{Save a ICO image file. (The size may be up to 255 wide by 127 high. A single image is saved in 8 colors at the size supplied.)}
\end{twocollist}}
\docparam{mimetype}{MIME type.}
@ -676,6 +706,33 @@ Specifies whether there is a mask or not. The area of the mask is determined by
Sets the mask colour for this image (and tells the image to use the mask).
\membersection{wxImage::SetMaskFromImage}\label{wximagesetmaskfromimage}
\func{bool}{SetMaskFromImage}{\param{const wxImage\&}{ mask}, \param{unsigned char}{ mr}, \param{unsigned char}{ mg}, \param{unsigned char}{ mb}}
\wxheading{Parameters}
\docparam{mask}{The mask image to extract mask shape from. Must have same dimensions as the image.}
\docparam{mr,mg,mb}{RGB value of pixels in {\it mask} that will be used to create the mask.}
Sets image's mask so that the pixels that have RGB value of {\it mr,mg,mb}
in {\it mask} will be masked in the image. This is done by first finding an
unused colour in the image, setting this colour as the mask colour and then
using this colour to draw all pixels in the image who corresponding pixel
in {\it mask} has given RGB value.
\wxheading{Return value}
Returns FALSE if {\it mask} does not have same dimensions as the image or if
there is no unused colour left. Returns TRUE if the mask was successfully
applied.
\wxheading{Notes}
Note that this method involves computing the histogram, which is
computationally intensive operation.
\membersection{wxImage::SetOption}\label{wximagesetoption}
\func{void}{SetOption}{\param{const wxString\&}{ name}, \param{const wxString\&}{ value}}

View File

@ -56,6 +56,7 @@ public:
virtual bool DoCanRead( wxInputStream& stream );
protected:
bool SaveDib(wxImage *image, wxOutputStream& stream, bool verbose, bool IsBmp, bool IsMask);
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 ) ;

View File

@ -47,7 +47,7 @@
#endif
//-----------------------------------------------------------------------------
// wxBMPHandler
// wxBMPHandler & wxICOHandler
//-----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
@ -56,9 +56,219 @@ IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
#if wxUSE_STREAMS
#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();
if (!cStream.Ok())
{
if (verbose)
wxLogError( _("ICO: Error calculating size of DIB .") );
return FALSE;
}
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 ;
}
bool wxBMPHandler::SaveFile(wxImage *image,
wxOutputStream& stream,
bool verbose)
{
bool IsBmp = TRUE;
bool IsMask = FALSE ;
return SaveDib( image, stream, verbose, IsBmp, IsMask ) ;
}
bool wxBMPHandler::SaveDib(wxImage *image,
wxOutputStream& stream,
bool verbose,
bool IsBmp,
bool IsMask)
{
wxCHECK_MSG( image, FALSE, _T("invalid pointer in wxBMPHandler::SaveFile") );
@ -145,7 +355,14 @@ bool wxBMPHandler::SaveFile(wxImage *image,
hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14);
hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth());
if (IsBmp)
{
hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight());
}
else
{
hdr.height = wxUINT32_SWAP_ON_BE(2 * image->GetHeight());
}
hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane
hdr.bpp = wxUINT16_SWAP_ON_BE(bpp);
hdr.compression = 0; // RGB uncompressed
@ -154,13 +371,25 @@ bool wxBMPHandler::SaveFile(wxImage *image,
hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap
hdr.num_signif_clrs = 0; // all colors are significant
if (IsBmp)
{
if (// VS: looks ugly but compilers tend to do ugly things with structs,
// like aligning hdr.filesize's ofset to dword :(
// VZ: we should add padding then...
!stream.Write(&hdr.magic, 2) ||
!stream.Write(&hdr.filesize, 4) ||
!stream.Write(&hdr.reserved, 4) ||
!stream.Write(&hdr.data_offset, 4) ||
!stream.Write(&hdr.data_offset, 4)
)
{
if (verbose)
wxLogError(_("BMP: Couldn't write the file (Bitmap) header."));
return FALSE;
}
}
if (!IsMask)
{
if (
!stream.Write(&hdr.bih_size, 4) ||
!stream.Write(&hdr.width, 4) ||
!stream.Write(&hdr.height, 4) ||
@ -175,9 +404,10 @@ bool wxBMPHandler::SaveFile(wxImage *image,
)
{
if (verbose)
wxLogError(_("BMP: Couldn't write the file header."));
wxLogError(_("BMP: Couldn't write the file (BitmapInfo) header."));
return FALSE;
}
}
wxPalette *palette = NULL; // entries for quantized images
wxUint8 *rgbquad = NULL; // for the RGBQUAD bytes for the colormap
@ -243,6 +473,8 @@ bool wxBMPHandler::SaveFile(wxImage *image,
// if the colormap was made, then it needs to be written
if (rgbquad)
{
if (!IsMask)
{
if (!stream.Write(rgbquad, palette_size*4))
{
if (verbose)
@ -254,6 +486,7 @@ bool wxBMPHandler::SaveFile(wxImage *image,
delete q_image;
return FALSE;
}
}
delete []rgbquad;
}
@ -397,40 +630,6 @@ bool wxBMPHandler::SaveFile(wxImage *image,
#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 wxBMPHandler::DoLoadDib (wxImage * image, int width, int height, int bpp, int ncolors, int comp,
off_t bmpOffset, wxInputStream& stream,
@ -911,16 +1110,9 @@ bool wxICOHandler::LoadFile ( wxImage *image, wxInputStream& stream, bool verbos
bResult = LoadDib ( image, stream, TRUE, IsBmp );
}
delete [] pIconDirEntry ;
return bResult
;
return bResult ;
}
bool wxICOHandler::SaveFile(wxImage *image,
wxOutputStream& stream,
bool verbose)
{
return FALSE ;
}
bool wxBMPHandler::DoCanRead( wxInputStream& stream )
{