added alpha channel support to wxImage

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@19455 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2003-03-03 20:33:40 +00:00
parent c0589c62a6
commit 487659e0fa
4 changed files with 280 additions and 101 deletions

View File

@@ -13,7 +13,6 @@ OTHER CHANGES
All:
- added wxCLOSE_BOX style for dialogs and frames
- added wxDateSpan::operator==() and !=() (Lukasz Michalski)
- use true/false throughout the library instead of TRUE/FALSE
- wxStopWatch::Start() resumes the stop watch if paused, as per the docs
@@ -30,6 +29,8 @@ wxBase:
All GUI ports:
- added alpha channel support to wxImage
- added wxCLOSE_BOX style for dialogs and frames
- added wxSplitterWindow handler to XRC
- added proportion to wxFlexGridSizer::AddGrowableRow/Col (Maxim Babitski)
- added wxFlexGridSizer::SetFlexibleDirection() (Szczepan Holyszewski)

View File

@@ -15,6 +15,22 @@ be drawn in a device context, using \helpref{wxDC::DrawBitmap}{wxdcdrawbitmap}.
One colour value of the image may be used as a mask colour which will lead to the automatic
creation of a \helpref{wxMask}{wxmask} object associated to the bitmap object.
\wxheading{Alpha channel support}
Starting from wxWindows 2.5.0 wxImage supports alpha channel data, that is in
addition to a byte for the red, green and blue colour components for each pixel
it also stores a byte representing the pixel opacity. The alpha value of $0$
corresponds to a transparent pixel (null opacity) while the value of $255$
means that the pixel is 100\% opaque.
Unlike the RGB data, not all images have the alpha channel and before using
\helpref{GetAlpha}{wximagegetalpha} you should check if this image contains
alpha value with \helpref{HasAlpha}{wximagehasalpha}. In fact, currently only
images loaded from PNG files with transparency information will have alpha
channel but support for it will be added to the other formats as well (as well
as support for saving images with alpha channel which is not still implemented
neither).
\wxheading{Available image handlers}
The following image handlers are available. {\bf wxBMPHandler} is always
@@ -25,7 +41,7 @@ handler with \helpref{wxImage::AddHandler}{wximageaddhandler} or
\twocolwidtha{5cm}%
\begin{twocollist}
\twocolitem{\indexit{wxBMPHandler}}{For loading and saving, always installed.}
\twocolitem{\indexit{wxPNGHandler}}{For loading and saving.}
\twocolitem{\indexit{wxPNGHandler}}{For loading (including alpha support) and saving.}
\twocolitem{\indexit{wxJPEGHandler}}{For loading and saving.}
\twocolitem{\indexit{wxGIFHandler}}{Only for loading, due to legal issues.}
\twocolitem{\indexit{wxPCXHandler}}{For loading and saving (see below).}
@@ -337,6 +353,25 @@ A pointer to the handler if found, NULL otherwise.
\helpref{wxImageHandler}{wximagehandler}
\membersection{wxImage::GetAlpha}\label{wximagegetalpha}
\constfunc{unsigned char}{GetAlpha}{\param{int}{ x}, \param{int}{ y}}
Returns the alpha value for the given pixel. This function may only be called
for the images with alpha channel, use \helpref{HasAlpha}{wximagehasalpha} to
check for this.
The returned value is the {\it opacity} of the image, i.e. the value of $0$
corresponds to the transparent pixels while the value of $255$ -- to the opaque
ones.
\constfunc{unsigned char *}{GetAlpha}{\void}
Returns pointer to the array storing the alpha values for this image. This
pointer is {\tt NULL} for the images without the alpha channel. If the image
does have it, this pointer may be used to directly manipulate the alpha values
which are stored as the \helpref{RGB}{wximagegetdata} ones.
\membersection{wxImage::GetBlue}\label{wximagegetblue}
\constfunc{unsigned char}{GetBlue}{\param{int}{ x}, \param{int}{ y}}
@@ -349,7 +384,9 @@ Returns the blue intensity at the given coordinate.
Returns the image data as an array. This is most often used when doing
direct image manipulation. The return value points to an array of
characters in RGBRGBRGB$\ldots$ format.
characters in RGBRGBRGB$\ldots$ format in the top-to-bottom, left-to-right
order, that is the first RGB triplet corresponds to the pixel $(0, 0)$, the
second one --- to $(0, 1)$ and so on.
You should not delete the returned pointer nor pass it to
\helpref{wxImage::SetData}{wximagesetdata}.
@@ -463,6 +500,16 @@ Gets the width of the image in pixels.
\helpref{wxImage::GetHeight}{wximagegetheight}
\membersection{wxImage::HasAlpha}\label{wximagehasalpha}
\constfunc{bool}{HasAlpha}{\void}
Returns true if this image has alpha channel, false otherwise.
\wxheading{See also}
\helpref{GetAlpha}{wximagegetalpha}, \helpref{SetAlpha}{wximagesetalpha}
\membersection{wxImage::HasMask}\label{wximagehasmask}
\constfunc{bool}{HasMask}{\void}
@@ -805,6 +852,23 @@ Example:
\helpref{Rescale}{wximagerescale}
\membersection{wxImage::SetAlpha}\label{wximagesetalpha}
\func{void}{SetAlpha}{\param{unsigned char *}{alpha = {\tt NULL}}}
This function is similar to \helpref{SetData}{wximagesetdata} and has similar
restrictions. The pointer passed to it may however be {\tt NULL} in which case
the function will allocate the alpha array internally -- this is useful to add
alpha channel data to an image which doesn't have any. If the pointer is not
{\tt NULL}, it must have one byte for each image pixel and be allocated with
{\tt malloc()}. wxImage takes ownership of the pointer and will free it.
\func{void}{SetAlpha}{\param{int }{x}, \param{int }{y}, \param{unsigned char }{alpha}}
Sets the alpha value for the given pixel. This function should only be called
if the image has alpha channel data, use \helpref{HasAlpha}{wximagehasalpha} to
check for this.
\membersection{wxImage::SetData}\label{wximagesetdata}
\func{void}{SetData}{\param{unsigned char*}{data}}
@@ -813,7 +877,8 @@ Sets the image data without performing checks. The data given must have
the size (width*height*3) or results will be unexpected. Don't use this
method if you aren't sure you know what you are doing.
The data must have been allocated with malloc(), NOT with operator new.
The data must have been allocated with {\tt malloc()}, {\large \bf NOT} with
{\tt operator new}.
After this call the pointer to the data is owned by the wxImage object,
that will be responsible for deleting it.

View File

@@ -100,7 +100,33 @@ public:
WX_DECLARE_EXPORTED_HASH_MAP(unsigned long, wxImageHistogramEntry,
wxIntegerHash, wxIntegerEqual,
wxImageHistogram);
wxImageHistogramBase);
class wxImageHistogram : public wxImageHistogramBase
{
public:
wxImageHistogram() : wxImageHistogramBase(256) { }
// get the key in the histogram for the given RGB values
static unsigned long MakeKey(unsigned char r,
unsigned char g,
unsigned char b)
{
return (r << 16) | (g << 8) | b;
}
// find first colour that is not used in the image and has higher
// RGB values than RGB(startR, startG, startB)
//
// returns true and puts this colour in r, g, b (each of which may be NULL)
// on success or returns false if there are no more free colours
bool FindFirstUnusedColour(unsigned char *r,
unsigned char *g,
unsigned char *b,
unsigned char startR = 1,
unsigned char startG = 0,
unsigned char startB = 0 ) const;
};
//-----------------------------------------------------------------------------
// wxImage
@@ -176,6 +202,9 @@ public:
unsigned char GetGreen( int x, int y ) const;
unsigned char GetBlue( int x, int y ) const;
void SetAlpha(int x, int y, unsigned char alpha);
unsigned char GetAlpha(int x, int y);
// find first colour that is not used in the image and has higher
// RGB values than <startR,startG,startB>
bool FindFirstUnusedColour( unsigned char *r, unsigned char *g, unsigned char *b,
@@ -210,9 +239,15 @@ public:
int GetWidth() const;
int GetHeight() const;
char unsigned *GetData() const;
void SetData( char unsigned *data );
void SetData( char unsigned *data, int new_width, int new_height );
// these functions provide fastest access to wxImage data but should be
// used carefully as no checks are done
unsigned char *GetData() const;
void SetData( unsigned char *data );
void SetData( unsigned char *data, int new_width, int new_height );
unsigned char *GetAlpha() const; // may return NULL!
bool HasAlpha() const { return GetAlpha() != NULL; }
void SetAlpha(unsigned char *alpha = NULL);
// Mask functions
void SetMaskColour( unsigned char r, unsigned char g, unsigned char b );

View File

@@ -50,18 +50,25 @@ class wxImageRefData: public wxObjectRefData
{
public:
wxImageRefData();
~wxImageRefData();
virtual ~wxImageRefData();
int m_width;
int m_height;
unsigned char *m_data;
bool m_hasMask;
unsigned char m_maskRed,m_maskGreen,m_maskBlue;
// alpha channel data, may be NULL for the formats without alpha support
unsigned char *m_alpha;
bool m_ok;
bool m_static;
#if wxUSE_PALETTE
wxPalette m_palette;
#endif // wxUSE_PALETTE
wxArrayString m_optionNames;
wxArrayString m_optionValues;
@@ -72,19 +79,24 @@ wxImageRefData::wxImageRefData()
{
m_width = 0;
m_height = 0;
m_data = (unsigned char*) NULL;
m_ok = FALSE;
m_data =
m_alpha = (unsigned char *) NULL;
m_maskRed = 0;
m_maskGreen = 0;
m_maskBlue = 0;
m_hasMask = FALSE;
m_ok = FALSE;
m_static = FALSE;
}
wxImageRefData::~wxImageRefData()
{
if (m_data && !m_static)
if ( !m_static )
free( m_data );
free(m_alpha);
}
wxList wxImage::sm_handlers;
@@ -198,7 +210,7 @@ wxImage wxImage::Copy() const
image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
char unsigned *data = image.GetData();
unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
@@ -331,7 +343,7 @@ wxImage wxImage::Scale( int width, int height ) const
}
image.Create( width, height );
char unsigned *data = image.GetData();
unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
@@ -342,8 +354,8 @@ wxImage wxImage::Scale( int width, int height ) const
M_IMGDATA->m_maskBlue );
}
char unsigned *source_data = M_IMGDATA->m_data;
char unsigned *target_data = data;
unsigned char *source_data = M_IMGDATA->m_data;
unsigned char *target_data = data;
#if 0
// This is nonsense, RR.
@@ -402,7 +414,7 @@ wxImage wxImage::Rotate90( bool clockwise ) const
image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width );
char unsigned *data = image.GetData();
unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
@@ -412,8 +424,8 @@ wxImage wxImage::Rotate90( bool clockwise ) const
long height = M_IMGDATA->m_height;
long width = M_IMGDATA->m_width;
char unsigned *source_data = M_IMGDATA->m_data;
char unsigned *target_data;
unsigned char *source_data = M_IMGDATA->m_data;
unsigned char *target_data;
for (long j = 0; j < height; j++)
{
@@ -439,7 +451,7 @@ wxImage wxImage::Mirror( bool horizontally ) const
image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
char unsigned *data = image.GetData();
unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
@@ -449,8 +461,8 @@ wxImage wxImage::Mirror( bool horizontally ) const
long height = M_IMGDATA->m_height;
long width = M_IMGDATA->m_width;
char unsigned *source_data = M_IMGDATA->m_data;
char unsigned *target_data;
unsigned char *source_data = M_IMGDATA->m_data;
unsigned char *target_data;
if (horizontally)
{
@@ -493,7 +505,7 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const
image.Create( subwidth, subheight );
char unsigned *subdata = image.GetData(), *data=GetData();
unsigned char *subdata = image.GetData(), *data=GetData();
wxCHECK_MSG( subdata, image, wxT("unable to create image") );
@@ -601,7 +613,7 @@ void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1,
{
wxCHECK_RET( Ok(), wxT("invalid image") );
char unsigned *data = GetData();
unsigned char *data = GetData();
const int w = GetWidth();
const int h = GetHeight();
@@ -627,7 +639,7 @@ wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char
image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
char unsigned *data = image.GetData();
unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
@@ -642,8 +654,8 @@ wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char
long size = M_IMGDATA->m_height * M_IMGDATA->m_width;
char unsigned *srcd = M_IMGDATA->m_data;
char unsigned *tard = image.GetData();
unsigned char *srcd = M_IMGDATA->m_data;
unsigned char *tard = image.GetData();
for ( long i = 0; i < size; i++, srcd += 3, tard += 3 )
{
@@ -722,14 +734,14 @@ bool wxImage::Ok() const
return data && data->m_ok && data->m_width && data->m_height;
}
char unsigned *wxImage::GetData() const
unsigned char *wxImage::GetData() const
{
wxCHECK_MSG( Ok(), (char unsigned *)NULL, wxT("invalid image") );
wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") );
return M_IMGDATA->m_data;
}
void wxImage::SetData( char unsigned *data )
void wxImage::SetData( unsigned char *data )
{
wxCHECK_RET( Ok(), wxT("invalid image") );
@@ -749,7 +761,7 @@ void wxImage::SetData( char unsigned *data )
m_refData = newRefData;
}
void wxImage::SetData( char unsigned *data, int new_width, int new_height )
void wxImage::SetData( unsigned char *data, int new_width, int new_height )
{
wxImageRefData *newRefData = new wxImageRefData();
@@ -777,6 +789,59 @@ void wxImage::SetData( char unsigned *data, int new_width, int new_height )
m_refData = newRefData;
}
// ----------------------------------------------------------------------------
// alpha channel support
// ----------------------------------------------------------------------------
void wxImage::SetAlpha(int x, int y, unsigned char alpha)
{
wxCHECK_RET( Ok() && HasAlpha(), wxT("invalid image or no alpha channel") );
int w = M_IMGDATA->m_width,
h = M_IMGDATA->m_height;
wxCHECK_RET( x >=0 && y >= 0 && x < w && y < h, wxT("invalid image index") );
M_IMGDATA->m_alpha[y*w + x] = alpha;
}
unsigned char wxImage::GetAlpha(int x, int y)
{
wxCHECK_MSG( Ok() && HasAlpha(), 0, wxT("invalid image or no alpha channel") );
int w = M_IMGDATA->m_width,
h = M_IMGDATA->m_height;
wxCHECK_MSG( x >=0 && y >= 0 && x < w && y < h, 0, wxT("invalid image index") );
return M_IMGDATA->m_alpha[y*w + x];
}
void wxImage::SetAlpha( unsigned char *alpha )
{
wxCHECK_RET( Ok(), wxT("invalid image") );
if ( !alpha )
{
alpha = (unsigned char *)
malloc(M_IMGDATA->m_width*M_IMGDATA->m_height*3);
}
delete [] M_IMGDATA->m_alpha;
M_IMGDATA->m_alpha = alpha;
}
unsigned char *wxImage::GetAlpha() const
{
wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") );
return M_IMGDATA->m_alpha;
}
// ----------------------------------------------------------------------------
// mask support
// ----------------------------------------------------------------------------
void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
{
wxCHECK_RET( Ok(), wxT("invalid image") );
@@ -836,73 +901,26 @@ int wxImage::GetHeight() const
return M_IMGDATA->m_height;
}
bool wxImage::FindFirstUnusedColour(
unsigned char *r, unsigned char *g, unsigned char *b,
unsigned char startR, unsigned char startG, unsigned char startB) const
{
wxImageHistogram histogram;
unsigned long key;
ComputeHistogram(histogram);
unsigned char r2 = startR;
unsigned char g2 = startG;
unsigned char b2 = startB;
key = (r2 << 16) | (g2 << 8) | b2;
while ( histogram.find(key) != histogram.end() )
{
// 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;
}
if (r) *r = r2;
if (g) *g = g2;
if (b) *b = b2;
return TRUE;
}
bool wxImage::SetMaskFromImage(const wxImage& mask,
bool wxImage::SetMaskFromImage(const wxImage& mask,
unsigned char mr, unsigned char mg, unsigned char mb)
{
// 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") );
wxLogError( _("Image and Mask have different sizes") );
return FALSE;
}
// find unused colour
unsigned char r,g,b ;
if (!FindFirstUnusedColour(&r, &g, &b))
{
wxLogError( _("No Unused Color in image being masked") );
wxLogError( _("No Unused Color in image being masked") );
return FALSE ;
}
char unsigned *imgdata = GetData();
char unsigned *maskdata = mask.GetData();
unsigned char *imgdata = GetData();
unsigned char *maskdata = mask.GetData();
const int w = GetWidth();
const int h = GetHeight();
@@ -924,7 +942,7 @@ bool wxImage::SetMaskFromImage(const wxImage& mask,
SetMaskColour(r, g, b);
SetMask(TRUE);
return TRUE;
}
@@ -1051,7 +1069,7 @@ bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype, int
bool wxImage::SaveFile( const wxString& filename ) const
{
wxString ext = filename.AfterLast('.').Lower();
wxImageHandler * pHandler = FindHandler(ext, -1);
if (pHandler)
{
@@ -1478,7 +1496,69 @@ wxImage::wxImage( const wxBitmap &bitmap )
#endif // WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI
//-----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// image histogram stuff
// ----------------------------------------------------------------------------
bool
wxImageHistogram::FindFirstUnusedColour(unsigned char *r,
unsigned char *g,
unsigned char *b,
unsigned char r2,
unsigned char b2,
unsigned char g2) const
{
unsigned long key = MakeKey(r2, g2, b2);
while ( find(key) != end() )
{
// 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 = MakeKey(r2, g2, b2);
}
if ( r )
*r = r2;
if ( g )
*g = g2;
if ( b )
*b = b2;
return TRUE;
}
bool
wxImage::FindFirstUnusedColour(unsigned char *r,
unsigned char *g,
unsigned char *b,
unsigned char r2,
unsigned char b2,
unsigned char g2) const
{
wxImageHistogram histogram;
ComputeHistogram(histogram);
return histogram.FindFirstUnusedColour(r, g, b, r2, g2, b2);
}
// GRG, Dic/99
// Counts and returns the number of different colours. Optionally stops
@@ -1504,7 +1584,7 @@ unsigned long wxImage::CountColours( unsigned long stopafter ) const
r = *(p++);
g = *(p++);
b = *(p++);
key = (r << 16) | (g << 8) | b;
key = wxImageHistogram::MakeKey(r, g, b);
if (h.Get(key) == NULL)
{
@@ -1519,24 +1599,22 @@ unsigned long wxImage::CountColours( unsigned long stopafter ) const
unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const
{
unsigned char r, g, b;
unsigned char *p;
unsigned long size, nentries, key;
unsigned char *p = GetData();
unsigned long nentries = 0;
h.clear();
p = GetData();
size = GetWidth() * GetHeight();
nentries = 0;
const unsigned long size = GetWidth() * GetHeight();
for (unsigned long j = 0; j < size; j++)
unsigned char r, g, b;
for ( unsigned long n = 0; n < size; n++ )
{
r = *(p++);
g = *(p++);
b = *(p++);
key = (r << 16) | (g << 8) | b;
r = *p++;
g = *p++;
b = *p++;
wxImageHistogramEntry& entry = h[wxImageHistogram::MakeKey(r, g, b)];
wxImageHistogramEntry& entry = h[key];
if ( entry.value++ == 0 )
entry.index = nentries++;
}