added wxImage::RotateHue() and RGB <-> HSV conversions (patch 1227108)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34969 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2005-07-28 22:50:34 +00:00
parent 278d457684
commit 978d3d3647
8 changed files with 299 additions and 7 deletions

View File

@ -10,6 +10,7 @@ All:
- Fixed wxScopeGuard to work with VC++, documented it.
- Fixed proxy handling in wxURL.
- Added wxZipFSHandler::Cleanup() (Stas Sergeev)
- Added wxImage::RotateHue() and RGB <-> HSV conversions (John Anderson)
All (GUI):

View File

@ -589,6 +589,26 @@ Gets the width of the image in pixels.
\helpref{wxImage::GetHeight}{wximagegetheight}
\membersection{HSVValue::HSVValue}\label{hsvvaluehsvvalue}
\func{}{HSVValue}{\param{double }{h = 0.0}, \param{double }{s = 0.0}, \param{double }{v = 0.0}}
Constructor for HSVValue, an object that contains values for hue, saturation and value which
represent the value of a color. It is used by \helpref{wxImage::HSVtoRGB}{wximagehsvtorgb}
and \helpref{wxImage::RGBtoHSV}{wximagergbtohsv}, which
converts between HSV color space and RGB color space.
\pythonnote{use wxImage\_HSVValue in wxPython}
\membersection{wxImage::HSVtoRGB}\label{wximagehsvtorgb}
\func{wxImage::RGBValue}{HSVtoRGB}{\param{const HSVValue \& }{hsv}}
Converts a color in HSV color space to RGB color space.
\membersection{wxImage::HasAlpha}\label{wximagehasalpha}
\constfunc{bool}{HasAlpha}{\void}
@ -810,6 +830,25 @@ mimetype from a file}
Returns true if image data is present.
\membersection{RGBValue::RGBValue}\label{rgbvaluergbvalue}
\func{}{RGBValue}{\param{unsigned char }{r = 0}, \param{unsigned char }{g = 0}, \param{unsigned char }{b = 0}}
Constructor for RGBValue, an object that contains values for red, green and blud which
represent the value of a color. It is used by \helpref{wxImage::HSVtoRGB}{wximagehsvtorgb}
and \helpref{wxImage::RGBtoHSV}{wximagergbtohsv}, which
converts between HSV color space and RGB color space.
\pythonnote{use wxImage\_RGBValue in wxPython}
\membersection{wxImage::RGBtoHSV}\label{wximagergbtohsv}
\func{wxImage::HSVValue}{RGBtoHSV}{\param{const RGBValue\& }{rgb}}
Converts a color in RGB color space to HSV color space.
\membersection{wxImage::RemoveHandler}\label{wximageremovehandler}
\func{static bool}{RemoveHandler}{\param{const wxString\& }{name}}
@ -889,6 +928,15 @@ rotated image background. Else, black (rgb 0, 0, 0) will be used.
Returns the rotated image, leaving this image intact.
\membersection{wxImage::RotateHue}\label{wximagerotatehue}
\func{void}{RotateHue}{\param{double}{ angle}}
Rotates the hue of each pixel in the image by {\it angle}, which is a double in
the range of -1.0 to +1.0, where -1.0 corresponds to -360 degrees and +1.0 corresponds
to +360 degrees.
\membersection{wxImage::Rotate90}\label{wximagerotate90}
\constfunc{wxImage}{Rotate90}{\param{bool}{ clockwise = true}}

View File

@ -157,6 +157,31 @@ public:
class WXDLLEXPORT wxImage: public wxObject
{
public:
#if wxABI_VERSION >= 20602
// red, green and blue are 8 bit unsigned integers in the range of 0..255
// We use the identifier RGBValue instead of RGB, since RGB is #defined
class RGBValue
{
public:
RGBValue(unsigned char r=0, unsigned char g=0, unsigned char b=0)
: red(r), green(g), blue(b) {}
unsigned char red;
unsigned char green;
unsigned char blue;
};
// hue, saturation and value are doubles in the range 0.0..1.0
class HSVValue
{
public:
HSVValue(double h=0.0, double s=0.0, double v=0.0)
: hue(h), saturation(s), value(v) {}
double hue;
double saturation;
double value;
};
#endif // wxABI_VERSION >= 2.6.2
wxImage(){}
wxImage( int width, int height, bool clear = true );
wxImage( int width, int height, unsigned char* data, bool static_data = false );
@ -337,6 +362,12 @@ public:
// Returned value: # of entries in the histogram
unsigned long ComputeHistogram( wxImageHistogram &h ) const;
#if wxABI_VERSION >= 20602
// 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 RotateHue(double angle);
#endif // wxABI_VERSION >= 2.6.2
wxImage& operator = (const wxImage& image)
{
if ( (*this) != image )
@ -363,6 +394,12 @@ public:
static void CleanUpHandlers();
static void InitStandardHandlers();
#if wxABI_VERSION >= 20602
static HSVValue RGBtoHSV(const RGBValue& rgb);
static RGBValue HSVtoRGB(const HSVValue& hsv);
#endif // wxABI_VERSION >= 2.6.2
protected:
static wxList sm_handlers;

View File

@ -84,6 +84,8 @@ public:
wxBitmap *my_horse_asciigrey_pnm;
wxBitmap *my_horse_rawgrey_pnm;
wxBitmap *colorized_horse_jpeg;
int xH, yH ;
int m_ani_images ;
@ -408,6 +410,7 @@ MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
my_horse_ico = (wxBitmap*) NULL;
my_horse_cur = (wxBitmap*) NULL;
my_horse_ani = (wxBitmap*) NULL;
colorized_horse_jpeg = (wxBitmap*) NULL;
my_smile_xbm = (wxBitmap*) NULL;
my_square = (wxBitmap*) NULL;
@ -465,7 +468,14 @@ MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
if ( !image.LoadFile( dir + _T("horse.jpg")) )
wxLogError(wxT("Can't load JPG image"));
else
{
my_horse_jpeg = new wxBitmap( image );
// Colorize by rotating green hue to red
wxImage::HSVValue greenHSV = wxImage::RGBtoHSV(wxImage::RGBValue(0, 255, 0));
wxImage::HSVValue redHSV = wxImage::RGBtoHSV(wxImage::RGBValue(255, 0, 0));
image.RotateHue(redHSV.hue - greenHSV.hue);
colorized_horse_jpeg = new wxBitmap( image );
}
#endif // wxUSE_LIBJPEG
#if wxUSE_GIF
@ -644,6 +654,7 @@ MyCanvas::~MyCanvas()
delete my_anti;
delete my_horse_asciigrey_pnm;
delete my_horse_rawgrey_pnm;
delete colorized_horse_jpeg;
}
void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
@ -843,6 +854,14 @@ void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
{
dc.DrawBitmap( my_horse_ani[i], 230 + i * 2 * my_horse_ani[i].GetWidth() , 2420, true );
}
#if wxUSE_LIBJPEG
if (colorized_horse_jpeg)
{
dc.DrawText( _T("Colorize image by rotating green hue to red"), 30, 2490 );
dc.DrawBitmap( *colorized_horse_jpeg, 30, 2520 );
}
#endif // wxUSE_LIBJPEG
}
void MyCanvas::CreateAntiAliasedBitmap()
@ -955,8 +974,8 @@ MyFrame::MyFrame()
m_canvas = new MyCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(10,10) );
// 500 width * 2500 height
m_canvas->SetScrollbars( 10, 10, 50, 250 );
// 500 width * 2750 height
m_canvas->SetScrollbars( 10, 10, 50, 275 );
}
void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )

View File

@ -42,11 +42,6 @@
// For memcpy
#include <string.h>
#ifdef __SALFORDC__
#undef FAR
#endif
//-----------------------------------------------------------------------------
// wxImage
//-----------------------------------------------------------------------------
@ -1758,6 +1753,159 @@ wxString wxImage::GetImageExtWildcard()
return wxT("(") + fmts + wxT(")|") + fmts;
}
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;
double minimumRGB = red;
if (green < minimumRGB)
minimumRGB = green;
if (blue < minimumRGB)
minimumRGB = blue;
double maximumRGB = red;
if (green > maximumRGB)
maximumRGB = green;
if (blue > maximumRGB)
maximumRGB = blue;
value = maximumRGB;
if (maximumRGB == minimumRGB)
{
// Gray has no color
hue = 0.0;
saturation = 0.0;
}
else
{
double deltaRGB = maximumRGB - minimumRGB;
saturation = deltaRGB / maximumRGB;
if ( red == maximumRGB )
hue = (green - blue) / deltaRGB;
else if (green == maximumRGB)
hue = 2.0 + (blue - red) / deltaRGB;
else
hue = 4.0 + (red - green) / deltaRGB;
hue = hue / 6.0;
if (hue < 0.0)
hue = hue + 1.0;
}
return HSVValue(hue, saturation, value);
}
wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv)
{
double red, green, blue;
if ( hsv.saturation == 0.0 )
{
red = hsv.value; //Grey
green = hsv.value;
blue = hsv.value;
}
else
{
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;
assert (angle >= -1.0 && angle <= 1.0);
count = M_IMGDATA->m_width * M_IMGDATA->m_height;
if (count > 0 && angle != 0.0)
{
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
//-----------------------------------------------------------------------------

View File

@ -14,6 +14,9 @@
*wxLogBuffer*;
*wxGenericListCtrl*SetItemFont*wxFont*;
*wxGenericListCtrl*GetItemFont*;
*wxImage*HSVValue*;
*wxImage*RGBValue*;
*wxImage*RotateHue*;
*wxMessageOutputBest*;
*wxShadowObject*;
*wxWizard*FinishLayout*;

View File

@ -555,6 +555,8 @@
%rename(IMAGE_ALPHA_OPAQUE) wxIMAGE_ALPHA_OPAQUE;
%rename(ImageHandler) wxImageHandler;
%rename(ImageHistogram) wxImageHistogram;
%rename(Image_RGBValue) wxImage_RGBValue;
%rename(Image_HSVValue) wxImage_HSVValue;
%rename(Image) wxImage;
%rename(NullImage) wxNullImage;
%rename(IMAGE_RESOLUTION_INCHES) wxIMAGE_RESOLUTION_INCHES;

View File

@ -155,6 +155,31 @@ Unlike RGB data, not all images have an alpha channel and before using
with `HasAlpha`. Note that currently only images loaded from PNG files
with transparency information will have an alpha channel.", "");
%{
// Pull the nested class out to the top level for SWIG's sake
#define wxImage_RGBValue wxImage::RGBValue
#define wxImage_HSVValue wxImage::HSVValue
%}
class wxImage_RGBValue
{
public:
wxImage_RGBValue(byte r=0, byte g=0, byte b=0);
byte red;
byte green;
byte blue;
};
class wxImage_HSVValue
{
public:
wxImage_HSVValue(double h=0.0, double s=0.0, double v=0.0);
double hue;
double saturation;
double value;
};
class wxImage : public wxObject {
public:
%typemap(out) wxImage*; // turn off this typemap
@ -888,6 +913,15 @@ MustHaveApp(ConvertToMonoBitmap);
}
}
DocDeclStr(
void , RotateHue(double angle),
"Rotates the hue of each pixel of the image. Hue is a double in the
range -1.0..1.0 where -1.0 is -360 degrees and 1.0 is 360 degrees", "");
static wxImage_HSVValue RGBtoHSV(wxImage_RGBValue rgb);
static wxImage_RGBValue HSVtoRGB(wxImage_HSVValue hsv);
%pythoncode { def __nonzero__(self): return self.Ok() }
};