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:
parent
278d457684
commit
978d3d3647
@ -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):
|
||||
|
||||
|
@ -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}}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) )
|
||||
|
@ -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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -14,6 +14,9 @@
|
||||
*wxLogBuffer*;
|
||||
*wxGenericListCtrl*SetItemFont*wxFont*;
|
||||
*wxGenericListCtrl*GetItemFont*;
|
||||
*wxImage*HSVValue*;
|
||||
*wxImage*RGBValue*;
|
||||
*wxImage*RotateHue*;
|
||||
*wxMessageOutputBest*;
|
||||
*wxShadowObject*;
|
||||
*wxWizard*FinishLayout*;
|
||||
|
@ -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;
|
||||
|
@ -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() }
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user