]> git.saurik.com Git - wxWidgets.git/commitdiff
added wxImage::RotateHue() and RGB <-> HSV conversions (patch 1227108)
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 28 Jul 2005 22:50:34 +0000 (22:50 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 28 Jul 2005 22:50:34 +0000 (22:50 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34969 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
docs/latex/wx/image.tex
include/wx/image.h
samples/image/image.cpp
src/common/image.cpp
version-script.in
wxPython/src/__core_rename.i
wxPython/src/_image.i

index 27915a87f916f34a5dec80ce0ff627332c27ff64..1a9d7c45126c6f3f621728c313b237fc20a1086a 100644 (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):
 
index 9cf68bb2a00dd5a8af521cf4d360417e643410a8..ccec15b3e852ab76f0cdda44f4d0c7645bb2548c 100644 (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}}
index 36843a4122bbd4f00cb4bf3dfc7ef5a9f2f6ecab..38f2809d9880dea10a321e8d24f667e2d6b34f65 100644 (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;
 
index 159f7fe26b450386455258542cdeae303eb4928b..98e014266701b558ee7d0b2c7dd227a26e07ce7f 100644 (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) )
index cf35689226e15f8141496be70a30af5869036b18..29562c0ebece1eebe155101ee89fab128013d334 100644 (file)
 // 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
 //-----------------------------------------------------------------------------
index cad768c7cc8339dce68ea5e5d0a696b6c5749e65..ad8db2dcf665da7899db11746c414cbbf69fa3b6 100644 (file)
@@ -14,6 +14,9 @@
         *wxLogBuffer*;
         *wxGenericListCtrl*SetItemFont*wxFont*;
         *wxGenericListCtrl*GetItemFont*;
+        *wxImage*HSVValue*;
+        *wxImage*RGBValue*;
+        *wxImage*RotateHue*;
         *wxMessageOutputBest*;
         *wxShadowObject*;
         *wxWizard*FinishLayout*;
index bf0f69771de58239f89c5d8feb239f0d12437721..a440c6d8f76fee759950f5390ad4b6cffb02c89d 100644 (file)
 %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;
index 62665aefbbd2512f703fe562b5b8e08901aa8da9..aceb32f72f642f81873f9af42a8ad4afc2f0e10e 100644 (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() }
 };