X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/921c65ed3d889117c600387cebb0bce2470cff8e..86948c99a6f0fd177b09b3db0ef702739ec62a27:/src/common/image.cpp diff --git a/src/common/image.cpp b/src/common/image.cpp index cf35689226..125e97613a 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" @@ -42,11 +38,6 @@ // For memcpy #include -#ifdef __SALFORDC__ - #undef FAR -#endif - - //----------------------------------------------------------------------------- // wxImage //----------------------------------------------------------------------------- @@ -157,17 +148,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); @@ -270,9 +250,18 @@ wxImage wxImage::Copy() const image.SetMask( M_IMGDATA->m_hasMask ); 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; @@ -389,7 +378,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); @@ -475,7 +464,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); @@ -778,6 +767,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; @@ -1563,7 +1592,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 ) @@ -1581,7 +1616,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 @@ -1758,6 +1799,177 @@ wxString wxImage::GetImageExtWildcard() return wxT("(") + fmts + wxT(")|") + fmts; } +wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb) +{ + 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 ) + minimumRGB = green; + if ( blue < minimumRGB ) + minimumRGB = blue; + + enum { RED, GREEN, BLUE } chMax = RED; + double maximumRGB = red; + if ( green > maximumRGB ) + { + chMax = GREEN; + maximumRGB = green; + } + if ( blue > maximumRGB ) + { + chMax = BLUE; + maximumRGB = blue; + } + + const double value = maximumRGB; + + double hue = 0.0, saturation; + const double deltaRGB = maximumRGB - minimumRGB; + if ( wxIsNullDouble(deltaRGB) ) + { + // Gray has no color + hue = 0.0; + saturation = 0.0; + } + else + { + switch ( chMax ) + { + case RED: + hue = (green - blue) / deltaRGB; + break; + + case GREEN: + hue = 2.0 + (blue - red) / deltaRGB; + break; + + case BLUE: + hue = 4.0 + (red - green) / deltaRGB; + break; + + default: + wxFAIL_MSG(wxT("hue not specified")); + break; + } + + hue /= 6.0; + + if ( hue < 0.0 ) + hue += 1.0; + + saturation = deltaRGB / maximumRGB; + } + + return HSVValue(hue, saturation, value); +} + +wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv) +{ + double red, green, blue; + + if ( wxIsNullDouble(hsv.saturation) ) + { + // Grey + red = hsv.value; + green = hsv.value; + blue = hsv.value; + } + else // not grey + { + double hue = hsv.hue * 6.0; // sector 0 to 5 + int i = (int)floor(hue); + double f = hue - i; // fractional part of h + double p = hsv.value * (1.0 - hsv.saturation); + + switch (i) + { + case 0: + red = hsv.value; + green = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + blue = p; + break; + + case 1: + red = hsv.value * (1.0 - hsv.saturation * f); + green = hsv.value; + blue = p; + break; + + case 2: + red = p; + green = hsv.value; + blue = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + break; + + case 3: + red = p; + green = hsv.value * (1.0 - hsv.saturation * f); + blue = hsv.value; + break; + + case 4: + red = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + green = p; + blue = hsv.value; + break; + + default: // case 5: + red = hsv.value; + green = p; + blue = hsv.value * (1.0 - hsv.saturation * f); + break; + } + } + + return RGBValue((unsigned char)(red * 255.0), + (unsigned char)(green * 255.0), + (unsigned char)(blue * 255.0)); +} + +/* + * Rotates the hue of each pixel of the image. angle is a double in the range + * -1.0..1.0 where -1.0 is -360 degrees and 1.0 is 360 degrees + */ +void wxImage::RotateHue(double angle) +{ + unsigned char *srcBytePtr; + unsigned char *dstBytePtr; + unsigned long count; + wxImage::HSVValue hsv; + wxImage::RGBValue rgb; + + wxASSERT (angle >= -1.0 && angle <= 1.0); + count = M_IMGDATA->m_width * M_IMGDATA->m_height; + if ( count > 0 && !wxIsNullDouble(angle) ) + { + srcBytePtr = M_IMGDATA->m_data; + dstBytePtr = srcBytePtr; + do + { + rgb.red = *srcBytePtr++; + rgb.green = *srcBytePtr++; + rgb.blue = *srcBytePtr++; + hsv = RGBtoHSV(rgb); + + hsv.hue = hsv.hue + angle; + if (hsv.hue > 1.0) + hsv.hue = hsv.hue - 1.0; + else if (hsv.hue < 0.0) + hsv.hue = hsv.hue + 1.0; + + rgb = HSVtoRGB(hsv); + *dstBytePtr++ = rgb.red; + *dstBytePtr++ = rgb.green; + *dstBytePtr++ = rgb.blue; + } while (--count != 0); + } +} + //----------------------------------------------------------------------------- // wxImageHandler //----------------------------------------------------------------------------- @@ -2017,20 +2229,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 @@ -2072,7 +2284,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) @@ -2080,8 +2292,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) @@ -2131,10 +2341,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) { @@ -2144,10 +2351,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) { @@ -2157,10 +2361,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) { @@ -2170,10 +2371,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 { @@ -2202,10 +2400,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 + @@ -2232,7 +2430,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 @@ -2246,10 +2444,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 {