/////////////////////////////////////////////////////////////////////////////
-// Name: image.cpp
+// Name: src/common/image.cpp
// Purpose: wxImage
// Author: Robert Roebling
// RCS-ID: $Id$
// 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"
// For memcpy
#include <string.h>
-#ifdef __SALFORDC__
- #undef FAR
-#endif
-
-
//-----------------------------------------------------------------------------
// wxImage
//-----------------------------------------------------------------------------
wxCHECK_MSG( data, image, wxT("unable to create image") );
+ unsigned char *source_data = M_IMGDATA->m_data;
+ unsigned char *target_data;
+ unsigned char *alpha_data = 0 ;
+ 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 );
+ }
+ else
+ {
+ source_alpha = M_IMGDATA->m_alpha ;
+ if ( source_alpha )
+ {
+ image.SetAlpha() ;
+ alpha_data = image.GetAlpha() ;
+ }
+ }
long height = M_IMGDATA->m_height;
long width = M_IMGDATA->m_width;
- unsigned char *source_data = M_IMGDATA->m_data;
- unsigned char *target_data;
-
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));
+ }
memcpy( target_data, source_data, 3 );
source_data += 3;
+
+ if(source_alpha)
+ {
+ memcpy( target_alpha, source_alpha, 1 );
+ source_alpha += 1;
+ }
}
}
return image;
}
+int wxImage::GetWidth() const
+{
+ wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+
+ return M_IMGDATA->m_width;
+}
+
+int wxImage::GetHeight() const
+{
+ wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+
+ return M_IMGDATA->m_height;
+}
+
long wxImage::XYToIndex(int x, int y) const
{
if ( Ok() &&
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.
src += 3, alpha++ )
{
*alpha = (src[0] == mr && src[1] == mg && src[2] == mb)
- ? ALPHA_TRANSPARENT
- : ALPHA_OPAQUE;
+ ? wxIMAGE_ALPHA_TRANSPARENT
+ : wxIMAGE_ALPHA_OPAQUE;
}
M_IMGDATA->m_hasMask = false;
else // no mask
{
// make the image fully opaque
- memset(alpha, ALPHA_OPAQUE, lenAlpha);
+ memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha);
}
}
return M_IMGDATA->m_hasMask;
}
-int wxImage::GetWidth() const
+bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const
{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+ long pos = XYToIndex(x, y);
+ wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") );
- return M_IMGDATA->m_width;
-}
+ // check mask
+ if ( M_IMGDATA->m_hasMask )
+ {
+ const unsigned char *p = M_IMGDATA->m_data + 3*pos;
+ if ( p[0] == M_IMGDATA->m_maskRed &&
+ p[1] == M_IMGDATA->m_maskGreen &&
+ p[2] == M_IMGDATA->m_maskBlue )
+ {
+ return true;
+ }
+ }
-int wxImage::GetHeight() const
-{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+ // then check alpha
+ if ( M_IMGDATA->m_alpha )
+ {
+ if ( M_IMGDATA->m_alpha[pos] < threshold )
+ {
+ // transparent enough
+ return true;
+ }
+ }
- return M_IMGDATA->m_height;
+ // not transparent
+ return false;
}
bool wxImage::SetMaskFromImage(const wxImage& mask,
return true;
}
-#if wxUSE_PALETTE
-
+// ----------------------------------------------------------------------------
// Palette functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
bool wxImage::HasPalette() const
{
#endif // wxUSE_PALETTE
+// ----------------------------------------------------------------------------
// Option functions (arbitrary name/value mapping)
+// ----------------------------------------------------------------------------
+
void wxImage::SetOption(const wxString& name, const wxString& value)
{
wxCHECK_RET( Ok(), wxT("invalid image") );
return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND);
}
+// ----------------------------------------------------------------------------
+// image I/O
+// ----------------------------------------------------------------------------
+
bool wxImage::LoadFile( const wxString& filename, long type, int index )
{
#if wxUSE_STREAMS
return false;
}
- return handler->LoadFile(this, stream, true/*verbose*/, index);
+ if (!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 )
return false;
}
- return handler->LoadFile( this, stream, true/*verbose*/, index );
+ if (!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
}
#endif // wxUSE_STREAMS
+// ----------------------------------------------------------------------------
+// image I/O handlers
+// ----------------------------------------------------------------------------
+
void wxImage::AddHandler( wxImageHandler *handler )
{
// Check for an existing handler of the type being added.
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
//-----------------------------------------------------------------------------
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
{
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)
// 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)
*(dst++) = *p;
if (has_alpha)
- {
- unsigned char *p = alpha[y1] + x1;
- *(alpha_dst++) = *p;
- }
+ *(alpha_dst++) = *(alpha[y1] + x1);
}
else if (d2 < gs_Epsilon)
{
*(dst++) = *p;
if (has_alpha)
- {
- unsigned char *p = alpha[y1] + x2;
- *(alpha_dst++) = *p;
- }
+ *(alpha_dst++) = *(alpha[y1] + x2);
}
else if (d3 < gs_Epsilon)
{
*(dst++) = *p;
if (has_alpha)
- {
- unsigned char *p = alpha[y2] + x2;
- *(alpha_dst++) = *p;
- }
+ *(alpha_dst++) = *(alpha[y2] + x2);
}
else if (d4 < gs_Epsilon)
{
*(dst++) = *p;
if (has_alpha)
- {
- unsigned char *p = alpha[y2] + x1;
- *(alpha_dst++) = *p;
- }
+ *(alpha_dst++) = *(alpha[y2] + x1);
}
else
{
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 +
{
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
*(dst++) = *p;
if (has_alpha)
- {
- unsigned char *p = alpha[ys] + (xs);
- *(alpha_dst++) = *p;
- }
+ *(alpha_dst++) = *(alpha[ys] + (xs));
}
else
{