X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c631d59053920f7c506c1d624a7811f3919d248d..cb0791531fff2f3673e28d68be67a0ee5398a036:/src/common/image.cpp diff --git a/src/common/image.cpp b/src/common/image.cpp index 179dae70ec..204c4b6657 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -7,7 +7,7 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "image.h" #endif @@ -32,10 +32,11 @@ #include "wx/intl.h" #include "wx/module.h" #include "wx/hash.h" +#include "wx/utils.h" +#include "wx/math.h" // For memcpy #include -#include #ifdef __SALFORDC__ #undef FAR @@ -93,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; @@ -109,10 +111,6 @@ wxImage wxNullImage; IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) -wxImage::wxImage() -{ -} - wxImage::wxImage( int width, int height, bool clear ) { Create( width, height, clear ); @@ -123,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 ); @@ -196,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(); @@ -218,6 +239,11 @@ wxImage wxImage::Copy() const memcpy( data, GetData(), M_IMGDATA->m_width*M_IMGDATA->m_height*3 ); + // also copy the image options + wxImageRefData *imgData = (wxImageRefData *)image.m_refData; + imgData->m_optionNames = M_IMGDATA->m_optionNames; + imgData->m_optionValues = M_IMGDATA->m_optionValues; + return image; } @@ -225,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") ); @@ -236,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") ); @@ -253,20 +279,32 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const 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 ; 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; - + else + { + source_alpha = M_IMGDATA->m_alpha ; + if ( source_alpha ) + { + image.SetAlpha() ; + target_alpha = image.GetAlpha() ; + } + } + for (long y = 0; y < height; y++) { for (long x = 0; x < width; x++) @@ -274,6 +312,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const 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 ) @@ -285,11 +324,18 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const 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++ ; } } @@ -302,9 +348,11 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const } else { - *(target_data++) = avgRed / counter ; - *(target_data++) = avgGreen / counter ; - *(target_data++) = avgBlue / counter ; + 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); } } } @@ -346,15 +394,26 @@ wxImage wxImage::Scale( int width, int height ) const 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; @@ -365,15 +424,19 @@ wxImage wxImage::Scale( int width, int height ) const 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; } @@ -790,7 +853,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") ); @@ -802,6 +865,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") ); @@ -811,7 +901,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; } @@ -822,6 +912,44 @@ 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; + + static const unsigned char ALPHA_TRANSPARENT = 0; + static const unsigned char ALPHA_OPAQUE = 0xff; + 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) + ? ALPHA_TRANSPARENT + : ALPHA_OPAQUE; + } + + M_IMGDATA->m_hasMask = false; + } + else // no mask + { + // make the image fully opaque + memset(alpha, ALPHA_OPAQUE, lenAlpha); + } +} + // ---------------------------------------------------------------------------- // mask support // ---------------------------------------------------------------------------- @@ -891,7 +1019,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; } @@ -899,7 +1027,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 ; } @@ -930,6 +1058,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 @@ -996,8 +1164,6 @@ wxString wxImage::GetOption(const wxString& name) const int wxImage::GetOptionInt(const wxString& name) const { - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - return wxAtoi(GetOption(name)); } @@ -1127,7 +1293,7 @@ bool wxImage::CanRead( wxInputStream &stream ) { const wxList& list = GetHandlers(); - for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() ) + for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) { wxImageHandler *handler=(wxImageHandler*)node->GetData(); if (handler->CanRead( stream )) @@ -1145,7 +1311,7 @@ int wxImage::GetImageCount( wxInputStream &stream, long type ) { wxList &list=GetHandlers(); - for (wxList::Node *node = list.GetFirst(); node; node = node->GetNext()) + for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) { handler=(wxImageHandler*)node->GetData(); if ( handler->CanRead(stream) ) @@ -1188,7 +1354,7 @@ bool wxImage::LoadFile( wxInputStream& stream, long type, int index ) { wxList &list=GetHandlers(); - for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() ) + for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) { handler=(wxImageHandler*)node->GetData(); if ( handler->CanRead(stream) ) @@ -1265,9 +1431,6 @@ bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const void wxImage::AddHandler( wxImageHandler *handler ) { - // make sure that the memory will be freed at the program end - sm_handlers.DeleteContents(true); - // Check for an existing handler of the type being added. if (FindHandler( handler->GetType() ) == 0) { @@ -1289,9 +1452,6 @@ void wxImage::AddHandler( wxImageHandler *handler ) void wxImage::InsertHandler( wxImageHandler *handler ) { - // make sure that the memory will be freed at the program end - sm_handlers.DeleteContents(true); - // Check for an existing handler of the type being added. if (FindHandler( handler->GetType() ) == 0) { @@ -1312,6 +1472,7 @@ bool wxImage::RemoveHandler( const wxString& name ) if (handler) { sm_handlers.DeleteObject(handler); + delete handler; return true; } else @@ -1320,7 +1481,7 @@ bool wxImage::RemoveHandler( const wxString& name ) wxImageHandler *wxImage::FindHandler( const wxString& name ) { - wxNode *node = sm_handlers.GetFirst(); + wxList::compatibility_iterator node = sm_handlers.GetFirst(); while (node) { wxImageHandler *handler = (wxImageHandler*)node->GetData(); @@ -1333,7 +1494,7 @@ wxImageHandler *wxImage::FindHandler( const wxString& name ) wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType ) { - wxNode *node = sm_handlers.GetFirst(); + wxList::compatibility_iterator node = sm_handlers.GetFirst(); while (node) { wxImageHandler *handler = (wxImageHandler*)node->GetData(); @@ -1347,7 +1508,7 @@ wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType wxImageHandler *wxImage::FindHandler( long bitmapType ) { - wxNode *node = sm_handlers.GetFirst(); + wxList::compatibility_iterator node = sm_handlers.GetFirst(); while (node) { wxImageHandler *handler = (wxImageHandler *)node->GetData(); @@ -1359,7 +1520,7 @@ wxImageHandler *wxImage::FindHandler( long bitmapType ) wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype ) { - wxNode *node = sm_handlers.GetFirst(); + wxList::compatibility_iterator node = sm_handlers.GetFirst(); while (node) { wxImageHandler *handler = (wxImageHandler *)node->GetData(); @@ -1378,24 +1539,24 @@ void wxImage::InitStandardHandlers() void wxImage::CleanUpHandlers() { - wxNode *node = sm_handlers.GetFirst(); + wxList::compatibility_iterator node = sm_handlers.GetFirst(); while (node) { wxImageHandler *handler = (wxImageHandler *)node->GetData(); - wxNode *next = node->GetNext(); + wxList::compatibility_iterator next = node->GetNext(); delete handler; - delete node; node = next; } -} + sm_handlers.Clear(); +} wxString wxImage::GetImageExtWildcard() { wxString fmts; wxList& Handlers = wxImage::GetHandlers(); - wxNode* Node = Handlers.GetFirst(); + wxList::compatibility_iterator Node = Handlers.GetFirst(); while ( Node ) { wxImageHandler* Handler = (wxImageHandler*)Node->GetData(); @@ -1407,7 +1568,6 @@ wxString wxImage::GetImageExtWildcard() return wxT("(") + fmts + wxT(")|") + fmts; } - //----------------------------------------------------------------------------- // wxImageHandler //----------------------------------------------------------------------------- @@ -1445,7 +1605,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 +1656,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 +1793,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 +1832,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 +1849,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 +1938,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 { @@ -1804,9 +2006,22 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i w3 * *(v3++) + w4 * *(v4++)) / (w1 + w2 + w3 + w4) ); *(dst++) = (unsigned char) - ( (w1 * *(v1++) + w2 * *(v2++) + - w3 * *(v3++) + w4 * *(v4++)) / + ( (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 +2029,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; } } } @@ -1835,13 +2053,22 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i unsigned char *p = data[ys] + (3 * xs); *(dst++) = *(p++); *(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 +2076,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i delete [] data; + if (has_alpha) + delete [] alpha; + return rotated; }