X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/978d3d3647fde4362cfe8b7b2b505ba1cc52770a..d68d85908b4f6073ae1c100abe3d9469fcd451d9:/src/common/image.cpp diff --git a/src/common/image.cpp b/src/common/image.cpp index 29562c0ebe..64f367c521 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: image.cpp +// Name: src/common/image.cpp // Purpose: wxImage // Author: Robert Roebling // RCS-ID: $Id$ @@ -7,10 +7,6 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "image.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -18,25 +14,26 @@ #pragma hdrstop #endif -#include "wx/defs.h" - #if wxUSE_IMAGE +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/hash.h" + #include "wx/utils.h" +#endif + #include "wx/image.h" #include "wx/bitmap.h" #include "wx/debug.h" -#include "wx/log.h" -#include "wx/app.h" #include "wx/filefn.h" #include "wx/wfstream.h" #include "wx/intl.h" #include "wx/module.h" -#include "wx/hash.h" -#include "wx/utils.h" #include "wx/math.h" #if wxUSE_XPM -#include "wx/xpmdecod.h" + #include "wx/xpmdecod.h" #endif // For memcpy @@ -152,17 +149,6 @@ wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index ) } #endif // wxUSE_STREAMS -wxImage::wxImage( const wxImage& image ) - : wxObject() -{ - Ref(image); -} - -wxImage::wxImage( const wxImage* image ) -{ - if (image) Ref(*image); -} - wxImage::wxImage( const char** xpmData ) { Create(xpmData); @@ -266,8 +252,17 @@ 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; + + // also copy the alpha channel + if (HasAlpha()) + { + image.SetAlpha(); + unsigned char* alpha = image.GetAlpha(); + memcpy( alpha, GetAlpha(), M_IMGDATA->m_width*M_IMGDATA->m_height ); + } + + // also copy the image options imgData->m_optionNames = M_IMGDATA->m_optionNames; imgData->m_optionValues = M_IMGDATA->m_optionValues; @@ -384,7 +379,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const } } - // In case this is a cursor, make sure the hotspot is scalled accordingly: + // In case this is a cursor, make sure the hotspot is scaled accordingly: if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X))/xFactor); @@ -470,7 +465,7 @@ wxImage wxImage::Scale( int width, int height ) const y += y_delta; } - // In case this is a cursor, make sure the hotspot is scalled accordingly: + // In case this is a cursor, make sure the hotspot is scaled accordingly: if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width); @@ -555,9 +550,16 @@ wxImage wxImage::Mirror( bool horizontally ) const 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 ); @@ -580,6 +582,25 @@ wxImage wxImage::Mirror( bool horizontally ) const target_data -= 3; } } + + if (alpha != NULL) + { + // src_alpha starts at the first pixel and increases by 1 after each step + // (a step here is the copy of the alpha value of one pixel) + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + // dest_alpha starts just beyond the first line, decreases before each step, + // and after each line is finished, increases by 2 widths (skipping the line + // just copied and the line that will be copied next) + unsigned char *dest_alpha = alpha + width; + + for (long jj = 0; jj < height; ++jj) + { + for (long i = 0; i < width; ++i) { + *(--dest_alpha) = *(src_alpha++); // copy one pixel + } + dest_alpha += 2 * width; // advance beyond the end of the next line + } + } } else { @@ -589,6 +610,23 @@ wxImage wxImage::Mirror( bool horizontally ) const memcpy( target_data, source_data, (size_t)3*width ); source_data += 3*width; } + + if (alpha != NULL) + { + // 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; @@ -600,32 +638,47 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()), + wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && + (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()), image, wxT("invalid subimage size") ); - int subwidth=rect.GetWidth(); - const int subheight=rect.GetHeight(); + const int subwidth = rect.GetWidth(); + const int subheight = rect.GetHeight(); image.Create( subwidth, subheight, false ); - unsigned char *subdata = image.GetData(), *data=GetData(); + 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 != NULL) { + 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 subleft=3*rect.GetLeft(); - const int width=3*GetWidth(); - subwidth*=3; + const int width = GetWidth(); + const int pixsoff = rect.GetLeft() + width * rect.GetTop(); - data+=rect.GetTop()*width+subleft; + 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, data, subwidth); - subdata+=subwidth; - data+=width; + 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; @@ -655,6 +708,10 @@ wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, wxRect subRect(pos.x, pos.y, width, height); wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight()); + if (pos.x < 0) + finalRect.width -= pos.x; + if (pos.y < 0) + finalRect.height -= pos.y; subRect.Intersect(finalRect); @@ -773,6 +830,46 @@ void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1, } } +wxImage wxImage::ConvertToGreyscale( double lr, double lg, double lb ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + 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 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); + } + else + { + // calculate the luma + double luma = (src[0] * lr + src[1] * lg + src[2] * lb) + 0.5; + dest[0] = dest[1] = dest[2] = wx_static_cast(unsigned char, luma); + } + } + + return image; +} + wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const { wxImage image; @@ -1558,7 +1655,13 @@ bool wxImage::LoadFile( wxInputStream& stream, long type, int index ) return false; } - return handler->LoadFile(this, stream, true/*verbose*/, index); + if (stream.IsSeekable() && !handler->CanRead(stream)) + { + wxLogError(_("Image file is not of type %d."), type); + return false; + } + else + return handler->LoadFile(this, stream, true/*verbose*/, index); } bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index ) @@ -1576,7 +1679,13 @@ bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int ind return false; } - return handler->LoadFile( this, stream, true/*verbose*/, index ); + if (stream.IsSeekable() && !handler->CanRead(stream)) + { + wxLogError(_("Image file is not of type %s."), (const wxChar*) mimetype); + return false; + } + else + return handler->LoadFile( this, stream, true/*verbose*/, index ); } bool wxImage::SaveFile( wxOutputStream& stream, int type ) const @@ -1755,29 +1864,36 @@ wxString wxImage::GetImageExtWildcard() wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb) { - double hue, saturation, value; - const double red = rgb.red / 255.0, green = rgb.green / 255.0, blue = rgb.blue / 255.0; + // find the min and max intensity (and remember which one was it for the + // latter) double minimumRGB = red; - if (green < minimumRGB) + if ( green < minimumRGB ) minimumRGB = green; - - if (blue < minimumRGB) + if ( blue < minimumRGB ) minimumRGB = blue; + enum { RED, GREEN, BLUE } chMax = RED; double maximumRGB = red; - if (green > maximumRGB) + if ( green > maximumRGB ) + { + chMax = GREEN; maximumRGB = green; - - if (blue > maximumRGB) + } + if ( blue > maximumRGB ) + { + chMax = BLUE; maximumRGB = blue; + } - value = maximumRGB; + const double value = maximumRGB; - if (maximumRGB == minimumRGB) + double hue = 0.0, saturation; + const double deltaRGB = maximumRGB - minimumRGB; + if ( wxIsNullDouble(deltaRGB) ) { // Gray has no color hue = 0.0; @@ -1785,21 +1901,31 @@ wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb) } else { - double deltaRGB = maximumRGB - minimumRGB; + switch ( chMax ) + { + case RED: + hue = (green - blue) / deltaRGB; + break; - saturation = deltaRGB / maximumRGB; + case GREEN: + hue = 2.0 + (blue - red) / deltaRGB; + break; - if ( red == maximumRGB ) - hue = (green - blue) / deltaRGB; - else if (green == maximumRGB) - hue = 2.0 + (blue - red) / deltaRGB; - else - hue = 4.0 + (red - green) / deltaRGB; + case BLUE: + hue = 4.0 + (red - green) / deltaRGB; + break; - hue = hue / 6.0; + default: + wxFAIL_MSG(wxT("hue not specified")); + break; + } + + hue /= 6.0; - if (hue < 0.0) - hue = hue + 1.0; + if ( hue < 0.0 ) + hue += 1.0; + + saturation = deltaRGB / maximumRGB; } return HSVValue(hue, saturation, value); @@ -1809,13 +1935,14 @@ wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv) { double red, green, blue; - if ( hsv.saturation == 0.0 ) + if ( wxIsNullDouble(hsv.saturation) ) { - red = hsv.value; //Grey + // Grey + red = hsv.value; green = hsv.value; - blue = hsv.value; + blue = hsv.value; } - else + else // not grey { double hue = hsv.hue * 6.0; // sector 0 to 5 int i = (int)floor(hue); @@ -1879,9 +2006,9 @@ void wxImage::RotateHue(double angle) wxImage::HSVValue hsv; wxImage::RGBValue rgb; - assert (angle >= -1.0 && angle <= 1.0); + wxASSERT (angle >= -1.0 && angle <= 1.0); count = M_IMGDATA->m_width * M_IMGDATA->m_height; - if (count > 0 && angle != 0.0) + if ( count > 0 && !wxIsNullDouble(angle) ) { srcBytePtr = M_IMGDATA->m_data; dstBytePtr = srcBytePtr; @@ -2165,20 +2292,20 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i wxRealPoint p3 = rotated_point (GetWidth(), 0, cos_angle, sin_angle, p0); wxRealPoint p4 = rotated_point (GetWidth(), GetHeight(), cos_angle, sin_angle, p0); - int x1 = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x))); - int y1 = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y))); - 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))); + int x1a = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x))); + int y1a = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y))); + int x2a = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x))); + int y2a = (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); + wxImage rotated (x2a - x1a + 1, y2a - y1a + 1, false); // With alpha channel if (has_alpha) rotated.SetAlpha(); if (offset_after_rotation != NULL) { - *offset_after_rotation = wxPoint (x1, y1); + *offset_after_rotation = wxPoint (x1a, y1a); } // GRG: The rotated (destination) image is always accessed @@ -2220,7 +2347,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i { for (x = 0; x < rotated.GetWidth(); x++) { - wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0); + wxRealPoint src = rotated_point (x + x1a, y + y1a, cos_angle, -sin_angle, p0); if (-0.25 < src.x && src.x < GetWidth() - 0.75 && -0.25 < src.y && src.y < GetHeight() - 0.75) @@ -2228,8 +2355,6 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i // interpolate using the 4 enclosing grid-points. Those // points can be obtained using floor and ceiling of the // exact coordinates of the point - // C.M. 2000-02-17: when the point is near the border, special care is required. - int x1, y1, x2, y2; if (0 < src.x && src.x < GetWidth() - 1) @@ -2279,10 +2404,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i *(dst++) = *p; if (has_alpha) - { - unsigned char *p = alpha[y1] + x1; - *(alpha_dst++) = *p; - } + *(alpha_dst++) = *(alpha[y1] + x1); } else if (d2 < gs_Epsilon) { @@ -2292,10 +2414,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i *(dst++) = *p; if (has_alpha) - { - unsigned char *p = alpha[y1] + x2; - *(alpha_dst++) = *p; - } + *(alpha_dst++) = *(alpha[y1] + x2); } else if (d3 < gs_Epsilon) { @@ -2305,10 +2424,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i *(dst++) = *p; if (has_alpha) - { - unsigned char *p = alpha[y2] + x2; - *(alpha_dst++) = *p; - } + *(alpha_dst++) = *(alpha[y2] + x2); } else if (d4 < gs_Epsilon) { @@ -2318,10 +2434,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i *(dst++) = *p; if (has_alpha) - { - unsigned char *p = alpha[y2] + x1; - *(alpha_dst++) = *p; - } + *(alpha_dst++) = *(alpha[y2] + x1); } else { @@ -2350,10 +2463,10 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i 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); + v1 = alpha[y1] + (x1); + v2 = alpha[y1] + (x2); + v3 = alpha[y2] + (x2); + v4 = alpha[y2] + (x1); *(alpha_dst++) = (unsigned char) ( (w1 * *v1 + w2 * *v2 + @@ -2380,7 +2493,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i { for (x = 0; x < rotated.GetWidth(); x++) { - wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0); + wxRealPoint src = rotated_point (x + x1a, y + y1a, cos_angle, -sin_angle, p0); const int xs = wxCint (src.x); // wxCint rounds to the const int ys = wxCint (src.y); // closest integer @@ -2394,10 +2507,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i *(dst++) = *p; if (has_alpha) - { - unsigned char *p = alpha[ys] + (xs); - *(alpha_dst++) = *p; - } + *(alpha_dst++) = *(alpha[ys] + (xs)); } else {