#include "wx/module.h"
#include "wx/hash.h"
#include "wx/utils.h"
+#include "wx/math.h"
+
+#if wxUSE_XPM
+#include "wx/xpmdecod.h"
+#endif
// For memcpy
#include <string.h>
-#include <math.h>
#ifdef __SALFORDC__
#undef FAR
unsigned char *m_alpha;
bool m_ok;
+
+ // if true, m_data is pointer to static data and shouldn't be freed
bool m_static;
+ // same as m_static but for m_alpha
+ bool m_staticAlpha;
+
#if wxUSE_PALETTE
wxPalette m_palette;
#endif // wxUSE_PALETTE
m_hasMask = false;
m_ok = false;
- m_static = false;
+ m_static =
+ m_staticAlpha = false;
}
wxImageRefData::~wxImageRefData()
{
- if (!m_static)
- {
+ if ( !m_static )
free( m_data );
+ if ( !m_staticAlpha )
free( m_alpha );
- }
}
wxList wxImage::sm_handlers;
if (image) Ref(*image);
}
+wxImage::wxImage( const char** xpmData )
+{
+ Create(xpmData);
+}
+
+wxImage::wxImage( char** xpmData )
+{
+ Create((const char**) xpmData);
+}
+
+bool wxImage::Create( const char** xpmData )
+{
+#if wxUSE_XPM
+ UnRef();
+
+ wxXPMDecoder decoder;
+ (*this) = decoder.ReadData(xpmData);
+ return Ok();
+#else
+ return false;
+#endif
+}
+
bool wxImage::Create( int width, int height, bool clear )
{
UnRef();
unsigned char maskRed = 0;
unsigned char maskGreen = 0;
unsigned char maskBlue =0 ;
+
+ unsigned char *source_data = M_IMGDATA->m_data;
+ unsigned char *target_data = data;
+ unsigned char *source_alpha = 0 ;
+ unsigned char *target_alpha = 0 ;
if (M_IMGDATA->m_hasMask)
{
hasMask = true ;
M_IMGDATA->m_maskGreen,
M_IMGDATA->m_maskBlue );
}
- char unsigned *source_data = M_IMGDATA->m_data;
- char unsigned *target_data = data;
+ else
+ {
+ source_alpha = M_IMGDATA->m_alpha ;
+ if ( source_alpha )
+ {
+ image.SetAlpha() ;
+ target_alpha = image.GetAlpha() ;
+ }
+ }
for (long y = 0; y < height; y++)
{
unsigned long avgRed = 0 ;
unsigned long avgGreen = 0;
unsigned long avgBlue = 0;
+ unsigned long avgAlpha = 0 ;
unsigned long counter = 0 ;
// determine average
for ( int y1 = 0 ; y1 < yFactor ; ++y1 )
unsigned char red = pixel[0] ;
unsigned char green = pixel[1] ;
unsigned char blue = pixel[2] ;
+ unsigned char alpha = 255 ;
+ if ( source_alpha )
+ alpha = *(source_alpha + y_offset + x * xFactor + x1) ;
if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue )
{
- avgRed += red ;
- avgGreen += green ;
- avgBlue += blue ;
+ if ( alpha > 0 )
+ {
+ avgRed += red ;
+ avgGreen += green ;
+ avgBlue += blue ;
+ }
+ avgAlpha += alpha ;
counter++ ;
}
}
}
else
{
+ if ( source_alpha )
+ *(target_alpha++) = (unsigned char)(avgAlpha / counter ) ;
*(target_data++) = (unsigned char)(avgRed / counter);
*(target_data++) = (unsigned char)(avgGreen / counter);
*(target_data++) = (unsigned char)(avgBlue / counter);
wxCHECK_MSG( data, image, wxT("unable to create image") );
+ unsigned char *source_data = M_IMGDATA->m_data;
+ unsigned char *target_data = data;
+ unsigned char *source_alpha = 0 ;
+ unsigned char *target_alpha = 0 ;
+
if (M_IMGDATA->m_hasMask)
{
image.SetMaskColour( M_IMGDATA->m_maskRed,
M_IMGDATA->m_maskGreen,
M_IMGDATA->m_maskBlue );
}
-
- unsigned char *source_data = M_IMGDATA->m_data;
- unsigned char *target_data = data;
+ else
+ {
+ source_alpha = M_IMGDATA->m_alpha ;
+ if ( source_alpha )
+ {
+ image.SetAlpha() ;
+ target_alpha = image.GetAlpha() ;
+ }
+ }
long x_delta = (old_width<<16) / width;
long y_delta = (old_height<<16) / height;
for ( long j = 0; j < height; j++ )
{
unsigned char* src_line = &source_data[(y>>16)*old_width*3];
+ unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ;
long x = 0;
for ( long i = 0; i < width; i++ )
{
unsigned char* src_pixel = &src_line[(x>>16)*3];
+ unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ;
dest_pixel[0] = src_pixel[0];
dest_pixel[1] = src_pixel[1];
dest_pixel[2] = src_pixel[2];
dest_pixel += 3;
+ if ( source_alpha )
+ *(target_alpha++) = *src_alpha_pixel ;
x += x_delta;
}
return image;
}
+wxImage wxImage::Size( const wxSize& size, const wxPoint& pos,
+ int r_, int g_, int b_ ) const
+{
+ wxImage image;
+
+ wxCHECK_MSG( Ok(), image, wxT("invalid image") );
+ wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") );
+
+ int width = GetWidth(), height = GetHeight();
+ image.Create(size.GetWidth(), size.GetHeight(), false);
+
+ unsigned char r = (unsigned char)r_;
+ unsigned char g = (unsigned char)g_;
+ unsigned char b = (unsigned char)b_;
+ if ((r_ == -1) && (g_ == -1) && (b_ == -1))
+ {
+ GetOrFindMaskColour( &r, &g, &b );
+ image.SetMaskColour(r, g, b);
+ }
+
+ image.SetRGB(wxRect(), r, g, b);
+
+ wxRect subRect(pos.x, pos.y, width, height);
+ wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight());
+
+ subRect.Intersect(finalRect);
+
+ if (!subRect.IsEmpty())
+ {
+ if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height))
+ image.Paste(*this, pos.x, pos.y);
+ else
+ image.Paste(GetSubImage(subRect), pos.x, pos.y);
+ }
+
+ return image;
+}
+
void wxImage::Paste( const wxImage &image, int x, int y )
{
wxCHECK_RET( Ok(), wxT("invalid image") );
if (height < 1) return;
if ((!HasMask() && !image.HasMask()) ||
+ (HasMask() && !image.HasMask()) ||
((HasMask() && image.HasMask() &&
(GetMaskRed()==image.GetMaskRed()) &&
(GetMaskGreen()==image.GetMaskGreen()) &&
return image;
}
-void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
+int wxImage::GetWidth() const
{
- wxCHECK_RET( Ok(), wxT("invalid image") );
+ wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+
+ return M_IMGDATA->m_width;
+}
+
+int wxImage::GetHeight() const
+{
+ wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+
+ return M_IMGDATA->m_height;
+}
+
+long wxImage::XYToIndex(int x, int y) const
+{
+ if ( Ok() &&
+ x >= 0 && y >= 0 &&
+ x < M_IMGDATA->m_width && y < M_IMGDATA->m_height )
+ {
+ return y*M_IMGDATA->m_width + x;
+ }
- int w = M_IMGDATA->m_width;
- int h = M_IMGDATA->m_height;
+ return -1;
+}
- wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
+void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
+{
+ long pos = XYToIndex(x, y);
+ wxCHECK_RET( pos != -1, wxT("invalid image coordinates") );
- long pos = (y * w + x) * 3;
+ pos *= 3;
M_IMGDATA->m_data[ pos ] = r;
M_IMGDATA->m_data[ pos+1 ] = g;
M_IMGDATA->m_data[ pos+2 ] = b;
}
-unsigned char wxImage::GetRed( int x, int y ) const
+void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b )
{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+ wxCHECK_RET( Ok(), wxT("invalid image") );
- int w = M_IMGDATA->m_width;
- int h = M_IMGDATA->m_height;
+ wxRect rect(rect_);
+ wxRect imageRect(0, 0, GetWidth(), GetHeight());
+ if ( rect == wxRect() )
+ {
+ rect = imageRect;
+ }
+ else
+ {
+ wxCHECK_RET( imageRect.Inside(rect.GetTopLeft()) &&
+ imageRect.Inside(rect.GetBottomRight()),
+ wxT("invalid bounding rectangle") );
+ }
+
+ int x1 = rect.GetLeft(),
+ y1 = rect.GetTop(),
+ x2 = rect.GetRight() + 1,
+ y2 = rect.GetBottom() + 1;
+
+ unsigned char *data wxDUMMY_INITIALIZE(NULL);
+ int x, y, width = GetWidth();
+ for (y = y1; y < y2; y++)
+ {
+ data = M_IMGDATA->m_data + (y*width + x1)*3;
+ for (x = x1; x < x2; x++)
+ {
+ *data++ = r;
+ *data++ = g;
+ *data++ = b;
+ }
+ }
+}
- wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
+unsigned char wxImage::GetRed( int x, int y ) const
+{
+ long pos = XYToIndex(x, y);
+ wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
- long pos = (y * w + x) * 3;
+ pos *= 3;
return M_IMGDATA->m_data[pos];
}
unsigned char wxImage::GetGreen( int x, int y ) const
{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
-
- int w = M_IMGDATA->m_width;
- int h = M_IMGDATA->m_height;
+ long pos = XYToIndex(x, y);
+ wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
- wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
-
- long pos = (y * w + x) * 3;
+ pos *= 3;
return M_IMGDATA->m_data[pos+1];
}
unsigned char wxImage::GetBlue( int x, int y ) const
{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
-
- int w = M_IMGDATA->m_width;
- int h = M_IMGDATA->m_height;
-
- wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
+ long pos = XYToIndex(x, y);
+ wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
- long pos = (y * w + x) * 3;
+ pos *= 3;
return M_IMGDATA->m_data[pos+2];
}
return M_IMGDATA->m_data;
}
-void wxImage::SetData( unsigned char *data )
+void wxImage::SetData( unsigned char *data, bool static_data )
{
wxCHECK_RET( Ok(), wxT("invalid image") );
newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
newRefData->m_hasMask = M_IMGDATA->m_hasMask;
+ newRefData->m_static = static_data;
UnRef();
m_refData = newRefData;
}
-void wxImage::SetData( unsigned char *data, int new_width, int new_height )
+void wxImage::SetData( unsigned char *data, int new_width, int new_height, bool static_data )
{
wxImageRefData *newRefData = new wxImageRefData();
newRefData->m_data = data;
newRefData->m_ok = true;
}
+ newRefData->m_static = static_data;
UnRef();
void wxImage::SetAlpha(int x, int y, unsigned char alpha)
{
- wxCHECK_RET( Ok() && HasAlpha(), wxT("invalid image or no alpha channel") );
+ wxCHECK_RET( HasAlpha(), wxT("no alpha channel") );
- int w = M_IMGDATA->m_width,
- h = M_IMGDATA->m_height;
+ long pos = XYToIndex(x, y);
+ wxCHECK_RET( pos != -1, wxT("invalid image coordinates") );
- wxCHECK_RET( x >=0 && y >= 0 && x < w && y < h, wxT("invalid image index") );
-
- M_IMGDATA->m_alpha[y*w + x] = alpha;
+ M_IMGDATA->m_alpha[pos] = alpha;
}
unsigned char wxImage::GetAlpha(int x, int y) const
{
- 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( HasAlpha(), 0, wxT("no alpha channel") );
- wxCHECK_MSG( x >=0 && y >= 0 && x < w && y < h, 0, wxT("invalid image index") );
+ long pos = XYToIndex(x, y);
+ wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
- return M_IMGDATA->m_alpha[y*w + x];
+ return M_IMGDATA->m_alpha[pos];
}
-bool wxImage::ConvertColourToAlpha( unsigned char r, unsigned char g, unsigned char b )
+bool
+wxImage::ConvertColourToAlpha(unsigned char r, unsigned char g, unsigned char b)
{
- SetAlpha( NULL );
-
- int w = M_IMGDATA->m_width,
- h = M_IMGDATA->m_height;
-
+ SetAlpha(NULL);
+
+ const int w = M_IMGDATA->m_width;
+ const int h = M_IMGDATA->m_height;
+
unsigned char *alpha = GetAlpha();
unsigned char *data = GetData();
-
- int x,y;
- for (y = 0; y < h; y++)
- for (x = 0; x < w; x++)
- {
- *alpha = *data;
- alpha++;
- *data = r;
- data++;
- *data = g;
- data++;
- *data = b;
- data++;
- }
+
+ for ( int y = 0; y < h; y++ )
+ {
+ for ( int x = 0; x < w; x++ )
+ {
+ *alpha++ = *data;
+ *data++ = r;
+ *data++ = g;
+ *data++ = b;
+ }
+ }
return true;
}
-void wxImage::SetAlpha( unsigned char *alpha )
+void wxImage::SetAlpha( unsigned char *alpha, bool static_data )
{
wxCHECK_RET( Ok(), wxT("invalid image") );
free(M_IMGDATA->m_alpha);
M_IMGDATA->m_alpha = alpha;
+ M_IMGDATA->m_staticAlpha = static_data;
}
unsigned char *wxImage::GetAlpha() const
return M_IMGDATA->m_alpha;
}
+void wxImage::InitAlpha()
+{
+ wxCHECK_RET( !HasAlpha(), wxT("image already has an alpha channel") );
+
+ // initialize memory for alpha channel
+ SetAlpha();
+
+ unsigned char *alpha = M_IMGDATA->m_alpha;
+ const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height;
+
+ if ( HasMask() )
+ {
+ // use the mask to initialize the alpha channel.
+ const unsigned char * const alphaEnd = alpha + lenAlpha;
+
+ const unsigned char mr = M_IMGDATA->m_maskRed;
+ const unsigned char mg = M_IMGDATA->m_maskGreen;
+ const unsigned char mb = M_IMGDATA->m_maskBlue;
+ for ( unsigned char *src = M_IMGDATA->m_data;
+ alpha < alphaEnd;
+ src += 3, alpha++ )
+ {
+ *alpha = (src[0] == mr && src[1] == mg && src[2] == mb)
+ ? wxIMAGE_ALPHA_TRANSPARENT
+ : wxIMAGE_ALPHA_OPAQUE;
+ }
+
+ M_IMGDATA->m_hasMask = false;
+ }
+ else // no mask
+ {
+ // make the image fully opaque
+ memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha);
+ }
+}
+
// ----------------------------------------------------------------------------
// mask support
// ----------------------------------------------------------------------------
M_IMGDATA->m_hasMask = true;
}
+bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const
+{
+ wxCHECK_MSG( Ok(), false, wxT("invalid image") );
+
+ if (M_IMGDATA->m_hasMask)
+ {
+ if (r) *r = M_IMGDATA->m_maskRed;
+ if (g) *g = M_IMGDATA->m_maskGreen;
+ if (b) *b = M_IMGDATA->m_maskBlue;
+ return true;
+ }
+ else
+ {
+ FindFirstUnusedColour(r, g, b);
+ return false;
+ }
+}
+
unsigned char wxImage::GetMaskRed() const
{
wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
return M_IMGDATA->m_hasMask;
}
-int wxImage::GetWidth() const
+bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const
{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+ long pos = XYToIndex(x, y);
+ wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") );
- return M_IMGDATA->m_width;
-}
+ // check mask
+ if ( M_IMGDATA->m_hasMask )
+ {
+ const unsigned char *p = M_IMGDATA->m_data + 3*pos;
+ if ( p[0] == M_IMGDATA->m_maskRed &&
+ p[1] == M_IMGDATA->m_maskGreen &&
+ p[2] == M_IMGDATA->m_maskBlue )
+ {
+ return true;
+ }
+ }
-int wxImage::GetHeight() const
-{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+ // then check alpha
+ if ( M_IMGDATA->m_alpha )
+ {
+ if ( M_IMGDATA->m_alpha[pos] < threshold )
+ {
+ // transparent enough
+ return true;
+ }
+ }
- return M_IMGDATA->m_height;
+ // not transparent
+ return false;
}
bool wxImage::SetMaskFromImage(const wxImage& mask,
return true;
}
-#if wxUSE_PALETTE
-
+// ----------------------------------------------------------------------------
// Palette functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
bool wxImage::HasPalette() const
{
#endif // wxUSE_PALETTE
+// ----------------------------------------------------------------------------
// Option functions (arbitrary name/value mapping)
+// ----------------------------------------------------------------------------
+
void wxImage::SetOption(const wxString& name, const wxString& value)
{
wxCHECK_RET( Ok(), wxT("invalid image") );
int wxImage::GetOptionInt(const wxString& name) const
{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
-
return wxAtoi(GetOption(name));
}
return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND);
}
+// ----------------------------------------------------------------------------
+// image I/O
+// ----------------------------------------------------------------------------
+
bool wxImage::LoadFile( const wxString& filename, long type, int index )
{
#if wxUSE_STREAMS
bool wxImage::SaveFile( const wxString& filename, int type ) const
{
#if wxUSE_STREAMS
+ wxCHECK_MSG( Ok(), false, wxT("invalid image") );
+
((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
wxFileOutputStream stream(filename);
bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype ) const
{
#if wxUSE_STREAMS
+ wxCHECK_MSG( Ok(), false, wxT("invalid image") );
+
((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
wxFileOutputStream stream(filename);
wxCHECK_MSG( Ok(), false, wxT("invalid image") );
wxImageHandler *handler = FindHandler(type);
-
- if (handler == 0)
+ if ( !handler )
{
wxLogWarning( _("No image handler for type %d defined."), type );
wxCHECK_MSG( Ok(), false, wxT("invalid image") );
wxImageHandler *handler = FindHandlerMime(mimetype);
-
- if (handler == 0)
+ if ( !handler )
{
wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
}
#endif // wxUSE_STREAMS
+// ----------------------------------------------------------------------------
+// image I/O handlers
+// ----------------------------------------------------------------------------
+
void wxImage::AddHandler( wxImageHandler *handler )
{
// Check for an existing handler of the type being added.
{
int i;
angle = -angle; // screen coordinates are a mirror image of "real" coordinates
-
+
bool has_alpha = HasAlpha();
// Create pointer-based array to accelerate access to wxImage's data
for (i = 1; i < GetHeight(); i++)
data[i] = data[i - 1] + (3 * GetWidth());
- // Same for alpha channel
+ // Same for alpha channel
unsigned char ** alpha = NULL;
if (has_alpha)
{
// array here (and in fact it would be slower).
//
unsigned char * dst = rotated.GetData();
-
+
unsigned char * alpha_dst = NULL;
if (has_alpha)
alpha_dst = rotated.GetAlpha();
*(dst++) = *(p++);
*(dst++) = *(p++);
*(dst++) = *p;
-
+
if (has_alpha)
{
unsigned char *p = alpha[y1] + x1;
*(dst++) = *(p++);
*(dst++) = *(p++);
*(dst++) = *p;
-
+
if (has_alpha)
{
unsigned char *p = alpha[y1] + x2;
*(dst++) = *(p++);
*(dst++) = *(p++);
*(dst++) = *p;
-
+
if (has_alpha)
{
unsigned char *p = alpha[y2] + x2;
*(dst++) = *(p++);
*(dst++) = *(p++);
*(dst++) = *p;
-
+
if (has_alpha)
{
unsigned char *p = alpha[y2] + x1;
( (w1 * *v1 + w2 * *v2 +
w3 * *v3 + w4 * *v4) /
(w1 + w2 + w3 + w4) );
-
+
if (has_alpha)
{
unsigned char *v1 = alpha[y1] + (x1);
*(dst++) = blank_r;
*(dst++) = blank_g;
*(dst++) = blank_b;
-
+
if (has_alpha)
*(alpha_dst++) = 0;
}
*(dst++) = *(p++);
*(dst++) = *(p++);
*(dst++) = *p;
-
+
if (has_alpha)
{
unsigned char *p = alpha[ys] + (xs);
*(dst++) = blank_r;
*(dst++) = blank_g;
*(dst++) = blank_b;
-
+
if (has_alpha)
*(alpha_dst++) = 255;
}
}
delete [] data;
-
+
if (has_alpha)
delete [] alpha;