+ {
+ for (long i = 0; i < height; i++)
+ {
+ target_data = data + 3*width*(height-1-i);
+ memcpy( target_data, source_data, (size_t)3*width );
+ source_data += 3*width;
+ }
+
+ if ( alpha )
+ {
+ // src_alpha starts at the first pixel and increases by 1 width after each step
+ // (a step here is the copy of the alpha channel of an entire line)
+ const unsigned char *src_alpha = M_IMGDATA->m_alpha;
+ // dest_alpha starts just beyond the last line (beyond the whole image)
+ // and decreases by 1 width before each step
+ unsigned char *dest_alpha = alpha + width * height;
+
+ for (long jj = 0; jj < height; ++jj)
+ {
+ dest_alpha -= width;
+ memcpy( dest_alpha, src_alpha, (size_t)width );
+ src_alpha += width;
+ }
+ }
+ }
+
+ return image;
+}
+
+wxImage wxImage::GetSubImage( const wxRect &rect ) const
+{
+ wxImage image;
+
+ wxCHECK_MSG( IsOk(), image, wxT("invalid image") );
+
+ wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) &&
+ (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()),
+ image, wxT("invalid subimage size") );
+
+ const int subwidth = rect.GetWidth();
+ const int subheight = rect.GetHeight();
+
+ image.Create( subwidth, subheight, false );
+
+ const unsigned char *src_data = GetData();
+ const unsigned char *src_alpha = M_IMGDATA->m_alpha;
+ unsigned char *subdata = image.GetData();
+ unsigned char *subalpha = NULL;
+
+ wxCHECK_MSG( subdata, image, wxT("unable to create image") );
+
+ if ( src_alpha ) {
+ image.SetAlpha();
+ subalpha = image.GetAlpha();
+ wxCHECK_MSG( subalpha, image, wxT("unable to create alpha channel"));
+ }
+
+ if (M_IMGDATA->m_hasMask)
+ image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
+
+ const int width = GetWidth();
+ const int pixsoff = rect.GetLeft() + width * rect.GetTop();
+
+ src_data += 3 * pixsoff;
+ src_alpha += pixsoff; // won't be used if was NULL, so this is ok
+
+ for (long j = 0; j < subheight; ++j)
+ {
+ memcpy( subdata, src_data, 3 * subwidth );
+ subdata += 3 * subwidth;
+ src_data += 3 * width;
+ if (subalpha != NULL) {
+ memcpy( subalpha, src_alpha, subwidth );
+ subalpha += subwidth;
+ src_alpha += width;
+ }
+ }
+
+ return image;
+}
+
+wxImage wxImage::Size( const wxSize& size, const wxPoint& pos,
+ int r_, int g_, int b_ ) const
+{
+ wxImage image;
+
+ wxCHECK_MSG( IsOk(), 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);
+
+ // we have two coordinate systems:
+ // source: starting at 0,0 of source image
+ // destination starting at 0,0 of destination image
+ // Documentation says:
+ // "The image is pasted into a new image [...] at the position pos relative
+ // to the upper left of the new image." this means the transition rule is:
+ // "dest coord" = "source coord" + pos;
+
+ // calculate the intersection using source coordinates:
+ wxRect srcRect(0, 0, width, height);
+ wxRect dstRect(-pos, size);
+
+ srcRect.Intersect(dstRect);
+
+ if (!srcRect.IsEmpty())
+ {
+ // insertion point is needed in destination coordinates.
+ // NB: it is not always "pos"!
+ wxPoint ptInsert = srcRect.GetTopLeft() + pos;
+
+ if ((srcRect.GetWidth() == width) && (srcRect.GetHeight() == height))
+ image.Paste(*this, ptInsert.x, ptInsert.y);
+ else
+ image.Paste(GetSubImage(srcRect), ptInsert.x, ptInsert.y);
+ }
+
+ return image;
+}
+
+void wxImage::Paste( const wxImage &image, int x, int y )
+{
+ wxCHECK_RET( IsOk(), wxT("invalid image") );
+ wxCHECK_RET( image.IsOk(), wxT("invalid image") );
+
+ AllocExclusive();
+
+ int xx = 0;
+ int yy = 0;
+ int width = image.GetWidth();
+ int height = image.GetHeight();
+
+ if (x < 0)
+ {
+ xx = -x;
+ width += x;
+ }
+ if (y < 0)
+ {
+ yy = -y;
+ height += y;
+ }
+
+ if ((x+xx)+width > M_IMGDATA->m_width)
+ width = M_IMGDATA->m_width - (x+xx);
+ if ((y+yy)+height > M_IMGDATA->m_height)
+ height = M_IMGDATA->m_height - (y+yy);
+
+ if (width < 1) return;
+ if (height < 1) return;
+
+ // If we can, copy the data using memcpy() as this is the fastest way. But
+ // for this the image being pasted must have "compatible" mask with this
+ // one meaning that either it must not have one at all or it must use the
+ // same masked colour.
+ if ( !image.HasMask() ||
+ ((HasMask() &&
+ (GetMaskRed()==image.GetMaskRed()) &&
+ (GetMaskGreen()==image.GetMaskGreen()) &&
+ (GetMaskBlue()==image.GetMaskBlue()))) )
+ {
+ const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth());
+ int source_step = image.GetWidth()*3;
+
+ unsigned char* target_data = GetData() + 3*((x+xx) + (y+yy)*M_IMGDATA->m_width);
+ int target_step = M_IMGDATA->m_width*3;
+ for (int j = 0; j < height; j++)
+ {
+ memcpy( target_data, source_data, width*3 );
+ source_data += source_step;
+ target_data += target_step;
+ }
+ }
+
+ // Copy over the alpha channel from the original image
+ if ( image.HasAlpha() )
+ {
+ if ( !HasAlpha() )
+ InitAlpha();
+
+ const unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth();
+ int source_step = image.GetWidth();
+
+ unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width;
+ int target_step = M_IMGDATA->m_width;
+
+ for (int j = 0; j < height; j++,
+ source_data += source_step,
+ target_data += target_step)
+ {
+ memcpy( target_data, source_data, width );
+ }
+ }
+
+ if (!HasMask() && image.HasMask())
+ {
+ unsigned char r = image.GetMaskRed();
+ unsigned char g = image.GetMaskGreen();
+ unsigned char b = image.GetMaskBlue();
+
+ const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth());
+ int source_step = image.GetWidth()*3;
+
+ unsigned char* target_data = GetData() + 3*((x+xx) + (y+yy)*M_IMGDATA->m_width);
+ int target_step = M_IMGDATA->m_width*3;
+
+ for (int j = 0; j < height; j++)
+ {
+ for (int i = 0; i < width*3; i+=3)
+ {
+ if ((source_data[i] != r) ||
+ (source_data[i+1] != g) ||
+ (source_data[i+2] != b))
+ {
+ memcpy( target_data+i, source_data+i, 3 );
+ }
+ }
+ source_data += source_step;
+ target_data += target_step;
+ }
+ }
+}
+
+void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1,
+ unsigned char r2, unsigned char g2, unsigned char b2 )
+{
+ wxCHECK_RET( IsOk(), wxT("invalid image") );
+
+ AllocExclusive();
+
+ unsigned char *data = GetData();
+
+ const int w = GetWidth();
+ const int h = GetHeight();
+
+ for (int j = 0; j < h; j++)
+ for (int i = 0; i < w; i++)
+ {
+ if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1))
+ {
+ data[0] = r2;
+ data[1] = g2;
+ data[2] = b2;
+ }
+ data += 3;
+ }
+}
+
+wxImage wxImage::ConvertToGreyscale(void) const
+{
+ return ConvertToGreyscale(0.299, 0.587, 0.114);
+}
+
+wxImage wxImage::ConvertToGreyscale(double weight_r, double weight_g, double weight_b) const
+{
+ wxImage image(MakeEmptyClone());
+
+ wxCHECK( image.IsOk(), image );
+
+ const unsigned char *src = M_IMGDATA->m_data;
+ unsigned char *dest = image.GetData();
+
+ const bool hasMask = M_IMGDATA->m_hasMask;
+ const unsigned char maskRed = M_IMGDATA->m_maskRed;
+ const unsigned char maskGreen = M_IMGDATA->m_maskGreen;
+ const unsigned char maskBlue = M_IMGDATA->m_maskBlue;
+
+ const long size = M_IMGDATA->m_width * M_IMGDATA->m_height;
+ for ( long i = 0; i < size; i++, src += 3, dest += 3 )
+ {
+ memcpy(dest, src, 3);
+ // only modify non-masked pixels
+ if ( !hasMask || src[0] != maskRed || src[1] != maskGreen || src[2] != maskBlue )
+ {
+ wxColour::MakeGrey(dest + 0, dest + 1, dest + 2, weight_r, weight_g, weight_b);
+ }
+ }
+
+ // copy the alpha channel, if any
+ if ( image.HasAlpha() )
+ {
+ memcpy( image.GetAlpha(), GetAlpha(), GetWidth() * GetHeight() );
+ }
+
+ return image;
+}
+
+wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const
+{
+ wxImage image;
+
+ wxCHECK_MSG( IsOk(), image, wxT("invalid image") );
+
+ image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false );
+
+ unsigned char *data = image.GetData();
+
+ wxCHECK_MSG( data, image, wxT("unable to create image") );
+
+ if (M_IMGDATA->m_hasMask)
+ {
+ if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g &&
+ M_IMGDATA->m_maskBlue == b)
+ image.SetMaskColour( 255, 255, 255 );
+ else
+ image.SetMaskColour( 0, 0, 0 );
+ }
+
+ long size = M_IMGDATA->m_height * M_IMGDATA->m_width;
+
+ unsigned char *srcd = M_IMGDATA->m_data;
+ unsigned char *tard = image.GetData();
+
+ for ( long i = 0; i < size; i++, srcd += 3, tard += 3 )
+ {
+ bool on = (srcd[0] == r) && (srcd[1] == g) && (srcd[2] == b);
+ wxColourBase::MakeMono(tard + 0, tard + 1, tard + 2, on);
+ }
+
+ return image;
+}
+
+wxImage wxImage::ConvertToDisabled(unsigned char brightness) const
+{
+ wxImage image = *this;
+
+ unsigned char mr = image.GetMaskRed();
+ unsigned char mg = image.GetMaskGreen();
+ unsigned char mb = image.GetMaskBlue();
+
+ int width = image.GetWidth();
+ int height = image.GetHeight();
+ bool has_mask = image.HasMask();
+
+ for (int y = height-1; y >= 0; --y)
+ {
+ for (int x = width-1; x >= 0; --x)
+ {
+ unsigned char* data = image.GetData() + (y*(width*3))+(x*3);
+ unsigned char* r = data;
+ unsigned char* g = data+1;
+ unsigned char* b = data+2;
+
+ if (has_mask && (*r == mr) && (*g == mg) && (*b == mb))
+ continue;
+
+ wxColour::MakeDisabled(r, g, b, brightness);
+ }
+ }
+ return image;
+}
+
+int wxImage::GetWidth() const
+{
+ wxCHECK_MSG( IsOk(), 0, wxT("invalid image") );
+
+ return M_IMGDATA->m_width;
+}
+
+int wxImage::GetHeight() const
+{
+ wxCHECK_MSG( IsOk(), 0, wxT("invalid image") );
+
+ return M_IMGDATA->m_height;
+}
+
+wxBitmapType wxImage::GetType() const
+{
+ wxCHECK_MSG( IsOk(), wxBITMAP_TYPE_INVALID, wxT("invalid image") );
+
+ return M_IMGDATA->m_type;
+}
+
+void wxImage::SetType(wxBitmapType type)
+{
+ wxCHECK_RET( IsOk(), "must create the image before setting its type");
+
+ // type can be wxBITMAP_TYPE_INVALID to reset the image type to default
+ wxASSERT_MSG( type != wxBITMAP_TYPE_MAX, "invalid bitmap type" );
+
+ M_IMGDATA->m_type = type;
+}
+
+long wxImage::XYToIndex(int x, int y) const
+{
+ if ( IsOk() &&
+ x >= 0 && y >= 0 &&
+ x < M_IMGDATA->m_width && y < M_IMGDATA->m_height )
+ {
+ return y*M_IMGDATA->m_width + x;
+ }
+
+ return -1;
+}
+
+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") );
+
+ AllocExclusive();
+
+ pos *= 3;
+
+ M_IMGDATA->m_data[ pos ] = r;
+ M_IMGDATA->m_data[ pos+1 ] = g;
+ M_IMGDATA->m_data[ pos+2 ] = b;
+}
+
+void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b )
+{
+ wxCHECK_RET( IsOk(), wxT("invalid image") );
+
+ AllocExclusive();
+
+ wxRect rect(rect_);
+ wxRect imageRect(0, 0, GetWidth(), GetHeight());
+ if ( rect == wxRect() )
+ {
+ rect = imageRect;
+ }
+ else
+ {
+ wxCHECK_RET( imageRect.Contains(rect.GetTopLeft()) &&
+ imageRect.Contains(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;
+ }
+ }
+}
+
+unsigned char wxImage::GetRed( int x, int y ) const
+{
+ long pos = XYToIndex(x, y);
+ wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
+
+ pos *= 3;
+
+ return M_IMGDATA->m_data[pos];