X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a4dac1907bcc57fe6b2f22a30f8d33bdf2055b3b..42604e44bec70f5a26cabb26653f7ca1490fb04e:/src/common/image.cpp?ds=sidebyside diff --git a/src/common/image.cpp b/src/common/image.cpp index e13640c4d6..de87a34257 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -26,9 +26,9 @@ #include "wx/module.h" #include "wx/palette.h" #include "wx/intl.h" + #include "wx/colour.h" #endif -#include "wx/filefn.h" #include "wx/wfstream.h" #include "wx/xpmdecod.h" @@ -252,6 +252,43 @@ wxObjectRefData* wxImage::CloneRefData(const wxObjectRefData* that) const return refData_new; } +// returns a new image with the same dimensions, alpha, and mask as *this +// if on_its_side is true, width and height are swapped +wxImage wxImage::MakeEmptyClone(int flags) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxS("invalid image") ); + + long height = M_IMGDATA->m_height; + long width = M_IMGDATA->m_width; + + if ( flags & Clone_SwapOrientation ) + wxSwap( width, height ); + + if ( !image.Create( width, height, false ) ) + { + wxFAIL_MSG( wxS("unable to create image") ); + return image; + } + + if ( M_IMGDATA->m_alpha ) + { + image.SetAlpha(); + wxCHECK2_MSG( image.GetAlpha(), return wxImage(), + wxS("unable to create alpha channel") ); + } + + if ( M_IMGDATA->m_hasMask ) + { + image.SetMaskColour( M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue ); + } + + return image; +} + wxImage wxImage::Copy() const { wxImage image; @@ -294,11 +331,11 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const bool hasMask = false ; unsigned char maskRed = 0; unsigned char maskGreen = 0; - unsigned char maskBlue =0 ; + unsigned char maskBlue = 0 ; - unsigned char *source_data = M_IMGDATA->m_data; + const unsigned char *source_data = M_IMGDATA->m_data; unsigned char *target_data = data; - unsigned char *source_alpha = 0 ; + const unsigned char *source_alpha = 0 ; unsigned char *target_alpha = 0 ; if (M_IMGDATA->m_hasMask) { @@ -336,7 +373,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const long y_offset = (y * yFactor + y1) * old_width; for ( int x1 = 0 ; x1 < xFactor ; ++x1 ) { - unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ; + const unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ; unsigned char red = pixel[0] ; unsigned char green = pixel[1] ; unsigned char blue = pixel[2] ; @@ -405,23 +442,16 @@ wxImage::Scale( int width, int height, wxImageResizeQuality quality ) const if ( old_width == width && old_height == height ) return *this; - // resample the image using either the nearest neighbourhood, bilinear or - // bicubic method as specified - switch ( quality ) + if (quality == wxIMAGE_QUALITY_HIGH) { - case wxIMAGE_QUALITY_BICUBIC: - case wxIMAGE_QUALITY_BILINEAR: - // both of these algorithms should be used for up-sampling the - // image only, when down-sampling always use box averaging for best - // results - if ( width < old_width && height < old_height ) - image = ResampleBox(width, height); - else if ( quality == wxIMAGE_QUALITY_BILINEAR ) - image = ResampleBilinear(width, height); - else if ( quality == wxIMAGE_QUALITY_BICUBIC ) - image = ResampleBicubic(width, height); - break; + quality = (width < old_width && height < old_height) + ? wxIMAGE_QUALITY_BOX_AVERAGE + : wxIMAGE_QUALITY_BICUBIC; + } + // Resample the image using the method as specified. + switch ( quality ) + { case wxIMAGE_QUALITY_NEAREST: if ( old_width % width == 0 && old_width >= width && old_height % height == 0 && old_height >= height ) @@ -431,6 +461,18 @@ wxImage::Scale( int width, int height, wxImageResizeQuality quality ) const image = ResampleNearest(width, height); break; + + case wxIMAGE_QUALITY_BILINEAR: + image = ResampleBilinear(width, height); + break; + + case wxIMAGE_QUALITY_BICUBIC: + image = ResampleBicubic(width, height); + break; + + case wxIMAGE_QUALITY_BOX_AVERAGE: + image = ResampleBox(width, height); + break; } // If the original image has a mask, apply the mask to the new image @@ -461,9 +503,9 @@ wxImage wxImage::ResampleNearest(int width, int height) const wxCHECK_MSG( data, image, wxT("unable to create image") ); - unsigned char *source_data = M_IMGDATA->m_data; + const unsigned char *source_data = M_IMGDATA->m_data; unsigned char *target_data = data; - unsigned char *source_alpha = 0 ; + const unsigned char *source_alpha = 0 ; unsigned char *target_alpha = 0 ; if ( !M_IMGDATA->m_hasMask ) @@ -486,14 +528,14 @@ wxImage wxImage::ResampleNearest(int width, int height) const long y = 0; 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 ; + const unsigned char* src_line = &source_data[(y>>16)*old_width*3]; + const 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 ; + const unsigned char* src_pixel = &src_line[(x>>16)*3]; + const 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]; @@ -524,8 +566,8 @@ wxImage wxImage::ResampleBox(int width, int height) const const int scale_factor_x_2 = (int)(scale_factor_x / 2); const int scale_factor_y_2 = (int)(scale_factor_y / 2); - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* src_alpha = M_IMGDATA->m_alpha; + const unsigned char* src_data = M_IMGDATA->m_data; + const unsigned char* src_alpha = M_IMGDATA->m_alpha; unsigned char* dst_data = ret_image.GetData(); unsigned char* dst_alpha = NULL; @@ -552,16 +594,16 @@ wxImage wxImage::ResampleBox(int width, int height) const averaged_pixels = 0; sum_r = sum_g = sum_b = sum_a = 0.0; - for ( int j = int(src_y - scale_factor_y/2.0 + 1); - j <= int(src_y + scale_factor_y_2); + for ( int j = int(src_y - scale_factor_y/2.0 + 1), k = j; + j <= int(src_y + scale_factor_y_2) || j < k + 2; j++ ) { // We don't care to average pixels that don't exist (edges) if ( j < 0 || j > M_IMGDATA->m_height - 1 ) continue; - for ( int i = int(src_x - scale_factor_x/2.0 + 1); - i <= src_x + scale_factor_x_2; + for ( int i = int(src_x - scale_factor_x/2.0 + 1), e = i; + i <= src_x + scale_factor_x_2 || i < e + 2; i++ ) { // Don't average edge pixels @@ -598,8 +640,8 @@ wxImage wxImage::ResampleBilinear(int width, int height) const { // This function implements a Bilinear algorithm for resampling. wxImage ret_image(width, height, false); - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* src_alpha = M_IMGDATA->m_alpha; + const unsigned char* src_data = M_IMGDATA->m_data; + const unsigned char* src_alpha = M_IMGDATA->m_alpha; unsigned char* dst_data = ret_image.GetData(); unsigned char* dst_alpha = NULL; @@ -651,29 +693,29 @@ wxImage wxImage::ResampleBilinear(int width, int height) const int src_pixel_index10 = y_offset2 * M_IMGDATA->m_width + x_offset1; int src_pixel_index11 = y_offset2 * M_IMGDATA->m_width + x_offset2; - //first line + // first line r1 = src_data[src_pixel_index00 * 3 + 0] * dx1 + src_data[src_pixel_index01 * 3 + 0] * dx; g1 = src_data[src_pixel_index00 * 3 + 1] * dx1 + src_data[src_pixel_index01 * 3 + 1] * dx; b1 = src_data[src_pixel_index00 * 3 + 2] * dx1 + src_data[src_pixel_index01 * 3 + 2] * dx; if ( src_alpha ) a1 = src_alpha[src_pixel_index00] * dx1 + src_alpha[src_pixel_index01] * dx; - //second line + // second line r2 = src_data[src_pixel_index10 * 3 + 0] * dx1 + src_data[src_pixel_index11 * 3 + 0] * dx; g2 = src_data[src_pixel_index10 * 3 + 1] * dx1 + src_data[src_pixel_index11 * 3 + 1] * dx; b2 = src_data[src_pixel_index10 * 3 + 2] * dx1 + src_data[src_pixel_index11 * 3 + 2] * dx; if ( src_alpha ) a2 = src_alpha[src_pixel_index10] * dx1 + src_alpha[src_pixel_index11] * dx; - //result lines + // result lines - dst_data[0] = r1 * dy1 + r2 * dy; - dst_data[1] = g1 * dy1 + g2 * dy; - dst_data[2] = b1 * dy1 + b2 * dy; + dst_data[0] = static_cast(r1 * dy1 + r2 * dy); + dst_data[1] = static_cast(g1 * dy1 + g2 * dy); + dst_data[2] = static_cast(b1 * dy1 + b2 * dy); dst_data += 3; if ( src_alpha ) - *dst_alpha++ = a1 * dy1 + a2 * dy; + *dst_alpha++ = static_cast(a1 * dy1 + a2 * dy); } } @@ -728,8 +770,8 @@ wxImage wxImage::ResampleBicubic(int width, int height) const ret_image.Create(width, height, false); - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* src_alpha = M_IMGDATA->m_alpha; + const unsigned char* src_data = M_IMGDATA->m_data; + const unsigned char* src_alpha = M_IMGDATA->m_alpha; unsigned char* dst_data = ret_image.GetData(); unsigned char* dst_alpha = NULL; @@ -812,26 +854,14 @@ wxImage wxImage::ResampleBicubic(int width, int height) const // Blur in the horizontal direction wxImage wxImage::BlurHorizontal(int blurRadius) const { - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + wxImage ret_image(MakeEmptyClone()); - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_alpha = NULL; + wxCHECK( ret_image.Ok(), ret_image ); - // Check for a mask or alpha - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - else if ( M_IMGDATA->m_hasMask ) - { - ret_image.SetMaskColour(M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue); - } + const unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* dst_data = ret_image.GetData(); + const unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_alpha = ret_image.GetAlpha(); // number of pixels we average over const int blurArea = blurRadius*2 + 1; @@ -927,26 +957,14 @@ wxImage wxImage::BlurHorizontal(int blurRadius) const // Blur in the vertical direction wxImage wxImage::BlurVertical(int blurRadius) const { - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + wxImage ret_image(MakeEmptyClone()); - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_alpha = NULL; + wxCHECK( ret_image.Ok(), ret_image ); - // Check for a mask or alpha - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - else if ( M_IMGDATA->m_hasMask ) - { - ret_image.SetMaskColour(M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue); - } + const unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* dst_data = ret_image.GetData(); + const unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_alpha = ret_image.GetAlpha(); // number of pixels we average over const int blurArea = blurRadius*2 + 1; @@ -1054,62 +1072,144 @@ wxImage wxImage::Blur(int blurRadius) const wxImage wxImage::Rotate90( bool clockwise ) const { - wxImage image; + wxImage image(MakeEmptyClone(Clone_SwapOrientation)); - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + wxCHECK( image.Ok(), image ); - image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width, false ); + long height = M_IMGDATA->m_height; + long width = M_IMGDATA->m_width; - unsigned char *data = image.GetData(); + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) + { + int hot_x = GetOptionInt( wxIMAGE_OPTION_CUR_HOTSPOT_X ); + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, + clockwise ? hot_x : width - 1 - hot_x); + } - wxCHECK_MSG( data, image, wxT("unable to create image") ); + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) + { + int hot_y = GetOptionInt( wxIMAGE_OPTION_CUR_HOTSPOT_Y ); + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, + clockwise ? height - 1 - hot_y : hot_y); + } - unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *data = image.GetData(); unsigned char *target_data; - unsigned char *alpha_data = 0 ; - unsigned char *source_alpha = 0 ; - unsigned char *target_alpha = 0 ; - if (M_IMGDATA->m_hasMask) + // we rotate the image in 21-pixel (63-byte) wide strips + // to make better use of cpu cache - memory transfers + // (note: while much better than single-pixel "strips", + // our vertical strips will still generally straddle 64-byte cachelines) + for (long ii = 0; ii < width; ) { - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); + long next_ii = wxMin(ii + 21, width); + + for (long j = 0; j < height; j++) + { + const unsigned char *source_data + = M_IMGDATA->m_data + (j*width + ii)*3; + + for (long i = ii; i < next_ii; i++) + { + if ( clockwise ) + { + target_data = data + ((i + 1)*height - j - 1)*3; + } + else + { + target_data = data + (height*(width - 1 - i) + j)*3; + } + memcpy( target_data, source_data, 3 ); + source_data += 3; + } + } + + ii = next_ii; } - else + + const unsigned char *source_alpha = M_IMGDATA->m_alpha; + + if ( source_alpha ) { - source_alpha = M_IMGDATA->m_alpha ; - if ( source_alpha ) + unsigned char *alpha_data = image.GetAlpha(); + unsigned char *target_alpha = 0 ; + + for (long ii = 0; ii < width; ) { - image.SetAlpha() ; - alpha_data = image.GetAlpha() ; + long next_ii = wxMin(ii + 64, width); + + for (long j = 0; j < height; j++) + { + source_alpha = M_IMGDATA->m_alpha + j*width + ii; + + for (long i = ii; i < next_ii; i++) + { + if ( clockwise ) + { + target_alpha = alpha_data + (i+1)*height - j - 1; + } + else + { + target_alpha = alpha_data + height*(width - i - 1) + j; + } + + *target_alpha = *source_alpha++; + } + } + + ii = next_ii; } } + return image; +} + +wxImage wxImage::Rotate180() const +{ + wxImage image(MakeEmptyClone()); + + wxCHECK( image.Ok(), image ); + long height = M_IMGDATA->m_height; long width = M_IMGDATA->m_width; + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) + { + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, + width - 1 - GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)); + } + + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) + { + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, + height - 1 - GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)); + } + + unsigned char *data = image.GetData(); + unsigned char *alpha = image.GetAlpha(); + const unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data = data + width * height * 3; + for (long j = 0; j < height; j++) { for (long i = 0; i < width; i++) { - if (clockwise) - { - target_data = data + (((i+1)*height) - j - 1)*3; - if(source_alpha) - target_alpha = alpha_data + (((i+1)*height) - j - 1); - } - else - { - target_data = data + ((height*(width-1)) + j - (i*height))*3; - if(source_alpha) - target_alpha = alpha_data + ((height*(width-1)) + j - (i*height)); - } + target_data -= 3; memcpy( target_data, source_data, 3 ); source_data += 3; + } + } + + if ( alpha ) + { + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + unsigned char *dest_alpha = alpha + width * height; - if(source_alpha) + for (long j = 0; j < height; ++j) + { + for (long i = 0; i < width; ++i) { - memcpy( target_alpha, source_alpha, 1 ); - source_alpha += 1; + *(--dest_alpha) = *(src_alpha++); } } } @@ -1119,30 +1219,16 @@ wxImage wxImage::Rotate90( bool clockwise ) const wxImage wxImage::Mirror( bool horizontally ) const { - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + wxImage image(MakeEmptyClone()); - image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); - - unsigned char *data = image.GetData(); - unsigned char *alpha = NULL; - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - if (M_IMGDATA->m_alpha != NULL) { - image.SetAlpha(); - alpha = image.GetAlpha(); - wxCHECK_MSG( alpha, 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 ); + wxCHECK( image.Ok(), image ); long height = M_IMGDATA->m_height; long width = M_IMGDATA->m_width; - unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *data = image.GetData(); + unsigned char *alpha = image.GetAlpha(); + const unsigned char *source_data = M_IMGDATA->m_data; unsigned char *target_data; if (horizontally) @@ -1187,7 +1273,7 @@ wxImage wxImage::Mirror( bool horizontally ) const source_data += 3*width; } - if (alpha != NULL) + 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) @@ -1230,7 +1316,7 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const wxCHECK_MSG( subdata, image, wxT("unable to create image") ); - if (src_alpha != NULL) { + if ( src_alpha ) { image.SetAlpha(); subalpha = image.GetAlpha(); wxCHECK_MSG( subalpha, image, wxT("unable to create alpha channel")); @@ -1342,17 +1428,20 @@ void wxImage::Paste( const wxImage &image, int x, int y ) if (width < 1) return; if (height < 1) return; - if ((!HasMask() && !image.HasMask()) || - (HasMask() && !image.HasMask()) || - ((HasMask() && image.HasMask() && + // 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())))) + (GetMaskBlue()==image.GetMaskBlue()))) ) { - unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); + const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth()); int source_step = image.GetWidth()*3; - unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; + 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++) { @@ -1368,7 +1457,7 @@ void wxImage::Paste( const wxImage &image, int x, int y ) if ( !HasAlpha() ) InitAlpha(); - unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth(); + 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; @@ -1388,10 +1477,10 @@ void wxImage::Paste( const wxImage &image, int x, int y ) unsigned char g = image.GetMaskGreen(); unsigned char b = image.GetMaskBlue(); - unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); + const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth()); int source_step = image.GetWidth()*3; - unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; + 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++) @@ -1436,51 +1525,40 @@ void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1, } } -wxImage wxImage::ConvertToGreyscale( double lr, double lg, double lb ) const +wxImage wxImage::ConvertToGreyscale(void) const { - wxImage image; + return ConvertToGreyscale(0.299, 0.587, 0.114); +} - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); +wxImage wxImage::ConvertToGreyscale(double weight_r, double weight_g, double weight_b) const +{ + wxImage image(MakeEmptyClone()); - image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + wxCHECK( image.Ok(), image ); + const unsigned char *src = M_IMGDATA->m_data; unsigned char *dest = image.GetData(); - wxCHECK_MSG( dest, image, wxT("unable to create image") ); - - unsigned char *src = M_IMGDATA->m_data; - bool hasMask = M_IMGDATA->m_hasMask; - unsigned char maskRed = M_IMGDATA->m_maskRed; - unsigned char maskGreen = M_IMGDATA->m_maskGreen; - unsigned char maskBlue = M_IMGDATA->m_maskBlue; - - if ( hasMask ) - image.SetMaskColour(maskRed, maskGreen, maskBlue); + 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 ) { - // don't modify the mask - if ( hasMask && src[0] == maskRed && src[1] == maskGreen && src[2] == maskBlue ) + memcpy(dest, src, 3); + // only modify non-masked pixels + if ( !hasMask || src[0] != maskRed || src[1] != maskGreen || src[2] != maskBlue ) { - memcpy(dest, src, 3); - } - else - { - // calculate the luma - double luma = (src[0] * lr + src[1] * lg + src[2] * lb) + 0.5; - dest[0] = dest[1] = dest[2] = static_cast(luma); + wxColour::MakeGrey(dest + 0, dest + 1, dest + 2, weight_r, weight_g, weight_b); } } // copy the alpha channel, if any - if (HasAlpha()) + if ( image.HasAlpha() ) { - const size_t alphaSize = GetWidth() * GetHeight(); - unsigned char *alpha = (unsigned char*)malloc(alphaSize); - memcpy(alpha, GetAlpha(), alphaSize); - image.InitAlpha(); - image.SetAlpha(alpha); + memcpy( image.GetAlpha(), GetAlpha(), GetWidth() * GetHeight() ); } return image; @@ -1514,15 +1592,43 @@ wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char for ( long i = 0; i < size; i++, srcd += 3, tard += 3 ) { - if (srcd[0] == r && srcd[1] == g && srcd[2] == b) - tard[0] = tard[1] = tard[2] = 255; - else - tard[0] = tard[1] = tard[2] = 0; + 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( Ok(), 0, wxT("invalid image") ); @@ -1825,6 +1931,17 @@ void wxImage::InitAlpha() } } +void wxImage::ClearAlpha() +{ + wxCHECK_RET( HasAlpha(), wxT("image already doesn't have an alpha channel") ); + + if ( !M_IMGDATA->m_staticAlpha ) + free( M_IMGDATA->m_alpha ); + + M_IMGDATA->m_alpha = NULL; +} + + // ---------------------------------------------------------------------------- // mask support // ---------------------------------------------------------------------------- @@ -1977,7 +2094,7 @@ bool wxImage::SetMaskFromImage(const wxImage& mask, bool wxImage::ConvertAlphaToMask(unsigned char threshold) { if ( !HasAlpha() ) - return true; + return false; unsigned char mr, mg, mb; if ( !FindFirstUnusedColour(&mr, &mg, &mb) ) @@ -1986,17 +2103,16 @@ bool wxImage::ConvertAlphaToMask(unsigned char threshold) return false; } - ConvertAlphaToMask(mr, mg, mb, threshold); - return true; + return ConvertAlphaToMask(mr, mg, mb, threshold); } -void wxImage::ConvertAlphaToMask(unsigned char mr, +bool wxImage::ConvertAlphaToMask(unsigned char mr, unsigned char mg, unsigned char mb, unsigned char threshold) { if ( !HasAlpha() ) - return; + return false; AllocExclusive(); @@ -2027,6 +2143,8 @@ void wxImage::ConvertAlphaToMask(unsigned char mr, M_IMGDATA->m_alpha = NULL; M_IMGDATA->m_staticAlpha = false; + + return true; } // ---------------------------------------------------------------------------- @@ -2121,21 +2239,18 @@ bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), int WXUNUSED_UNLESS_STREAMS(index) ) { #if HAS_FILE_STREAMS - if (wxFileExists(filename)) + wxImageFileInputStream stream(filename); + if ( stream.IsOk() ) { - wxImageFileInputStream stream(filename); wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, type, index); + if ( LoadFile(bstream, type, index) ) + return true; } - else - { - wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); - return false; - } -#else // !HAS_FILE_STREAMS - return false; + wxLogError(_("Failed to load image from file \"%s\"."), filename); #endif // HAS_FILE_STREAMS + + return false; } bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), @@ -2143,21 +2258,18 @@ bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), int WXUNUSED_UNLESS_STREAMS(index) ) { #if HAS_FILE_STREAMS - if (wxFileExists(filename)) + wxImageFileInputStream stream(filename); + if ( stream.IsOk() ) { - wxImageFileInputStream stream(filename); wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, mimetype, index); + if ( LoadFile(bstream, mimetype, index) ) + return true; } - else - { - wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); - return false; - } -#else // !HAS_FILE_STREAMS - return false; + wxLogError(_("Failed to load image from file \"%s\"."), filename); #endif // HAS_FILE_STREAMS + + return false; } @@ -2284,7 +2396,7 @@ int wxImage::GetImageCount( wxInputStream &stream, wxBitmapType type ) if ( !handler ) { - wxLogWarning(_("No image handler for type %ld defined."), type); + wxLogWarning(_("No image handler for type %d defined."), type); return false; } @@ -2294,7 +2406,7 @@ int wxImage::GetImageCount( wxInputStream &stream, wxBitmapType type ) } else { - wxLogError(_("Image file is not of type %ld."), type); + wxLogError(_("Image file is not of type %d."), type); return 0; } } @@ -2306,10 +2418,20 @@ bool wxImage::DoLoad(wxImageHandler& handler, wxInputStream& stream, int index) const unsigned maxWidth = GetOptionInt(wxIMAGE_OPTION_MAX_WIDTH), maxHeight = GetOptionInt(wxIMAGE_OPTION_MAX_HEIGHT); + // Preserve the original stream position if possible to rewind back to it + // if we failed to load the file -- maybe the next handler that we try can + // succeed after us then. + wxFileOffset posOld = wxInvalidOffset; + if ( stream.IsSeekable() ) + posOld = stream.TellI(); + if ( !handler.LoadFile(this, stream, true/*verbose*/, index) ) - return false; + { + if ( posOld != wxInvalidOffset ) + stream.SeekI(posOld); - M_IMGDATA->m_type = handler.GetType(); + return false; + } // rescale the image to the specified size if needed if ( maxWidth || maxHeight ) @@ -2331,6 +2453,9 @@ bool wxImage::DoLoad(wxImageHandler& handler, wxInputStream& stream, int index) Rescale(width, height, wxIMAGE_QUALITY_HIGH); } + // Set this after Rescale, which currently does not preserve it + M_IMGDATA->m_type = handler.GetType(); + return true; } @@ -2342,6 +2467,17 @@ bool wxImage::LoadFile( wxInputStream& stream, wxBitmapType type, int index ) if ( type == wxBITMAP_TYPE_ANY ) { + if ( !stream.IsSeekable() ) + { + // The error message about image data format being unknown below + // would be misleading in this case as we are not even going to try + // any handlers because CanRead() never does anything for not + // seekable stream, so try to be more precise here. + wxLogError(_("Can't automatically determine the image format " + "for non-seekable input.")); + return false; + } + const wxList& list = GetHandlers(); for ( wxList::compatibility_iterator node = list.GetFirst(); node; @@ -2352,7 +2488,7 @@ bool wxImage::LoadFile( wxInputStream& stream, wxBitmapType type, int index ) return true; } - wxLogWarning( _("No handler found for image type.") ); + wxLogWarning( _("Unknown image data format.") ); return false; } @@ -2361,13 +2497,13 @@ bool wxImage::LoadFile( wxInputStream& stream, wxBitmapType type, int index ) handler = FindHandler(type); if ( !handler ) { - wxLogWarning( _("No image handler for type %ld defined."), type ); + wxLogWarning( _("No image handler for type %d defined."), type ); return false; } if ( stream.IsSeekable() && !handler->CanRead(stream) ) { - wxLogError(_("Image file is not of type %ld."), type); + wxLogError(_("This is not a %s."), handler->GetName()); return false; } @@ -2390,7 +2526,7 @@ bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int ind if ( stream.IsSeekable() && !handler->CanRead(stream) ) { - wxLogError(_("Image file is not of type %s."), mimetype); + wxLogError(_("Image is not of type %s."), mimetype); return false; } @@ -2790,15 +2926,15 @@ int wxImageHandler::GetImageCount( wxInputStream& stream ) bool wxImageHandler::CanRead( const wxString& name ) { - if (wxFileExists(name)) + wxImageFileInputStream stream(name); + if ( !stream.IsOk() ) { - wxImageFileInputStream stream(name); - return CanRead(stream); - } + wxLogError(_("Failed to check format of image file \"%s\"."), name); - wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() ); + return false; + } - return false; + return CanRead(stream); } bool wxImageHandler::CallDoCanRead(wxInputStream& stream)