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
\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).}
\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}}
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}.
\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}
\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}}
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.
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
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,
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 );
{
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;
{
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;
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") );
}
image.Create( width, height );
- char unsigned *data = image.GetData();
+ unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
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.
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") );
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++)
{
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") );
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)
{
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") );
{
wxCHECK_RET( Ok(), wxT("invalid image") );
- char unsigned *data = GetData();
+ unsigned char *data = GetData();
const int w = GetWidth();
const int h = GetHeight();
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") );
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 )
{
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") );
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();
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") );
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();
SetMaskColour(r, g, b);
SetMask(TRUE);
-
+
return TRUE;
}
bool wxImage::SaveFile( const wxString& filename ) const
{
wxString ext = filename.AfterLast('.').Lower();
-
+
wxImageHandler * pHandler = FindHandler(ext, -1);
if (pHandler)
{
#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
r = *(p++);
g = *(p++);
b = *(p++);
- key = (r << 16) | (g << 8) | b;
+ key = wxImageHistogram::MakeKey(r, g, b);
if (h.Get(key) == NULL)
{
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++;
}