X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/999836aacade840a5d9a0cbb5fad7b1d4de62c93..1aaf88d2208793f6a05f02c3e23ade668555d31e:/src/common/image.cpp diff --git a/src/common/image.cpp b/src/common/image.cpp index a5f3c35f48..0a12ff7847 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -33,10 +33,10 @@ #include "wx/module.h" #include "wx/hash.h" #include "wx/utils.h" +#include "wx/math.h" // For memcpy #include -#include #ifdef __SALFORDC__ #undef FAR @@ -94,10 +94,11 @@ wxImageRefData::wxImageRefData() wxImageRefData::~wxImageRefData() { - if ( !m_static ) + if (!m_static) + { free( m_data ); - - free(m_alpha); + free( m_alpha ); + } } wxList wxImage::sm_handlers; @@ -110,10 +111,6 @@ wxImage wxNullImage; IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) -wxImage::wxImage() -{ -} - wxImage::wxImage( int width, int height, bool clear ) { Create( width, height, clear ); @@ -124,6 +121,11 @@ wxImage::wxImage( int width, int height, unsigned char* data, bool static_data ) Create( width, height, data, static_data ); } +wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) +{ + Create( width, height, data, alpha, static_data ); +} + wxImage::wxImage( const wxString& name, long type, int index ) { LoadFile( name, type, index ); @@ -197,6 +199,24 @@ bool wxImage::Create( int width, int height, unsigned char* data, bool static_da return true; } +bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) +{ + UnRef(); + + wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); + + m_refData = new wxImageRefData(); + + M_IMGDATA->m_data = data; + M_IMGDATA->m_alpha = alpha; + M_IMGDATA->m_width = width; + M_IMGDATA->m_height = height; + M_IMGDATA->m_ok = true; + M_IMGDATA->m_static = static_data; + + return true; +} + void wxImage::Destroy() { UnRef(); @@ -231,7 +251,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const { if( xFactor == 1 && yFactor == 1 ) return Copy() ; - + wxImage image; wxCHECK_MSG( Ok(), image, wxT("invalid image") ); @@ -242,7 +262,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const long old_height = M_IMGDATA->m_height, old_width = M_IMGDATA->m_width; - + wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, wxT("invalid old image size") ); @@ -265,14 +285,14 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const maskRed = M_IMGDATA->m_maskRed; maskGreen = M_IMGDATA->m_maskGreen; maskBlue =M_IMGDATA->m_maskBlue ; - + image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); } char unsigned *source_data = M_IMGDATA->m_data; char unsigned *target_data = data; - + for (long y = 0; y < height; y++) { for (long x = 0; x < width; x++) @@ -796,7 +816,7 @@ void wxImage::SetAlpha(int x, int y, unsigned char alpha) M_IMGDATA->m_alpha[y*w + x] = alpha; } -unsigned char wxImage::GetAlpha(int x, int y) +unsigned char wxImage::GetAlpha(int x, int y) const { wxCHECK_MSG( Ok() && HasAlpha(), 0, wxT("invalid image or no alpha channel") ); @@ -808,6 +828,33 @@ unsigned char wxImage::GetAlpha(int x, int y) return M_IMGDATA->m_alpha[y*w + x]; } +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; + + 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++; + } + + return true; +} + void wxImage::SetAlpha( unsigned char *alpha ) { wxCHECK_RET( Ok(), wxT("invalid image") ); @@ -817,7 +864,7 @@ void wxImage::SetAlpha( unsigned char *alpha ) alpha = (unsigned char *)malloc(M_IMGDATA->m_width*M_IMGDATA->m_height); } - delete [] M_IMGDATA->m_alpha; + free(M_IMGDATA->m_alpha); M_IMGDATA->m_alpha = alpha; } @@ -897,7 +944,7 @@ bool wxImage::SetMaskFromImage(const wxImage& mask, // 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; } @@ -905,7 +952,7 @@ bool wxImage::SetMaskFromImage(const wxImage& mask, unsigned char r,g,b ; if (!FindFirstUnusedColour(&r, &g, &b)) { - wxLogError( _("No Unused Color in image being masked") ); + wxLogError( _("No unused colour in image being masked.") ); return false ; } @@ -936,6 +983,46 @@ bool wxImage::SetMaskFromImage(const wxImage& mask, return true; } +bool wxImage::ConvertAlphaToMask(unsigned char threshold) +{ + if (!HasAlpha()) + return true; + + unsigned char mr, mg, mb; + if (!FindFirstUnusedColour(&mr, &mg, &mb)) + { + wxLogError( _("No unused colour in image being masked.") ); + return false; + } + + SetMask(true); + SetMaskColour(mr, mg, mb); + + unsigned char *imgdata = GetData(); + unsigned char *alphadata = GetAlpha(); + + int w = GetWidth(); + int h = GetHeight(); + + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++, imgdata += 3, alphadata++) + { + if (*alphadata < threshold) + { + imgdata[0] = mr; + imgdata[1] = mg; + imgdata[2] = mb; + } + } + } + + free(M_IMGDATA->m_alpha); + M_IMGDATA->m_alpha = NULL; + + return true; +} + #if wxUSE_PALETTE // Palette functions @@ -1445,7 +1532,7 @@ bool wxImageHandler::CanRead( const wxString& name ) bool wxImageHandler::CallDoCanRead(wxInputStream& stream) { - off_t posOld = stream.TellI(); + wxFileOffset posOld = stream.TellI(); if ( posOld == wxInvalidOffset ) { // can't test unseekable stream @@ -1496,7 +1583,7 @@ wxImageHistogram::FindFirstUnusedColour(unsigned char *r, b2++; if ( b2 >= 255 ) { - wxLogError(_("GetUnusedColour:: No Unused Color in image ") ); + wxLogError(_("No unused colour in image.") ); return false; } } @@ -1633,14 +1720,24 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i 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 unsigned char ** data = new unsigned char * [GetHeight()]; - data[0] = GetData(); - for (i = 1; i < GetHeight(); i++) data[i] = data[i - 1] + (3 * GetWidth()); + // Same for alpha channel + unsigned char ** alpha = NULL; + if (has_alpha) + { + alpha = new unsigned char * [GetHeight()]; + alpha[0] = GetAlpha(); + for (i = 1; i < GetHeight(); i++) + alpha[i] = alpha[i - 1] + GetWidth(); + } + // precompute coefficients for rotation formula // (sine and cosine of the angle) const double cos_angle = cos(angle); @@ -1662,7 +1759,11 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x))); int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y))); + // Create rotated image wxImage rotated (x2 - x1 + 1, y2 - y1 + 1, false); + // With alpha channel + if (has_alpha) + rotated.SetAlpha(); if (offset_after_rotation != NULL) { @@ -1675,6 +1776,10 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i // unsigned char * dst = rotated.GetData(); + unsigned char * alpha_dst = NULL; + if (has_alpha) + alpha_dst = rotated.GetAlpha(); + // GRG: if the original image has a mask, use its RGB values // as the blank pixel, else, fall back to default (black). // @@ -1760,28 +1865,52 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i unsigned char *p = data[y1] + (3 * x1); *(dst++) = *(p++); *(dst++) = *(p++); - *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + { + unsigned char *p = alpha[y1] + x1; + *(alpha_dst++) = *p; + } } else if (d2 < gs_Epsilon) { unsigned char *p = data[y1] + (3 * x2); *(dst++) = *(p++); *(dst++) = *(p++); - *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + { + unsigned char *p = alpha[y1] + x2; + *(alpha_dst++) = *p; + } } else if (d3 < gs_Epsilon) { unsigned char *p = data[y2] + (3 * x2); *(dst++) = *(p++); *(dst++) = *(p++); - *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + { + unsigned char *p = alpha[y2] + x2; + *(alpha_dst++) = *p; + } } else if (d4 < gs_Epsilon) { unsigned char *p = data[y2] + (3 * x1); *(dst++) = *(p++); *(dst++) = *(p++); - *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + { + unsigned char *p = alpha[y2] + x1; + *(alpha_dst++) = *p; + } } else { @@ -1807,6 +1936,19 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i ( (w1 * *v1 + w2 * *v2 + w3 * *v3 + w4 * *v4) / (w1 + w2 + w3 + w4) ); + + if (has_alpha) + { + unsigned char *v1 = alpha[y1] + (x1); + unsigned char *v2 = alpha[y1] + (x2); + unsigned char *v3 = alpha[y2] + (x2); + unsigned char *v4 = alpha[y2] + (x1); + + *(alpha_dst++) = (unsigned char) + ( (w1 * *v1 + w2 * *v2 + + w3 * *v3 + w4 * *v4) / + (w1 + w2 + w3 + w4) ); + } } } else @@ -1814,6 +1956,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i *(dst++) = blank_r; *(dst++) = blank_g; *(dst++) = blank_b; + + if (has_alpha) + *(alpha_dst++) = 0; } } } @@ -1836,12 +1981,21 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i *(dst++) = *(p++); *(dst++) = *(p++); *(dst++) = *p; + + if (has_alpha) + { + unsigned char *p = alpha[ys] + (xs); + *(alpha_dst++) = *p; + } } else { *(dst++) = blank_r; *(dst++) = blank_g; *(dst++) = blank_b; + + if (has_alpha) + *(alpha_dst++) = 255; } } } @@ -1849,6 +2003,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i delete [] data; + if (has_alpha) + delete [] alpha; + return rotated; }