From 640f22a259f8c9600ab59a37fa1e56f2317844cb Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 14 Oct 2011 06:40:40 +0000 Subject: [PATCH] Add Classic's enhancements to image and add unittests. Still need to add buffer and stream support. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@69418 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- etg/image.py | 175 +++++++++++++++++++++++++++++++++++++--- unittests/test_image.py | 126 +++++++++++++++++++++++++++++ 2 files changed, 292 insertions(+), 9 deletions(-) create mode 100644 unittests/test_image.py diff --git a/etg/image.py b/etg/image.py index 38a70a02..aaa5aa14 100644 --- a/etg/image.py +++ b/etg/image.py @@ -1,6 +1,7 @@ #--------------------------------------------------------------------------- # Name: etg/image.py # Author: Kevin Ollivier +# Robin Dunn # # Created: 25-Aug-2011 # Copyright: (c) 2011 by Wide Open Technologies @@ -17,8 +18,11 @@ DOCSTRING = "" # The classes and/or the basename of the Doxygen XML files to be processed by # this script. -ITEMS = [ 'wxImage', 'wxImageHistogram' ] - +ITEMS = [ 'wxImage', + 'wxImageHistogram', + #'wxImageHandler', # TODO + ] + #--------------------------------------------------------------------------- def run(): @@ -31,16 +35,22 @@ def run(): # customizing the generated code and docstrings. c = module.find('wxImage') + assert isinstance(c, etgtools.ClassDef) c.find('wxImage').findOverload('(const char *const *xpmData)').ignore() - c.find('GetHandlers').ignore() + c.find('GetHandlers').ignore() + c.find('AddHandler').ignore() + c.find('InsertHandler').ignore() + c.find('RemoveHandler').ignore() + for m in c.find('FindHandler').all(): + m.ignore() + c.find('FindHandlerMime').ignore() + + # TODO: Port the ctors and methods that deal with data buffers for getting # and setting the image and alpha data. - # TODO: Add these later when return types are defined. - c.find('RGBtoHSV').ignore() - c.find('HSVtoRGB').ignore() - + def setParamsPyInt(name): """Set the pyInt flag on 'unsigned char' params""" method = c.find(name) @@ -59,7 +69,7 @@ def run(): setParamsPyInt('SetMaskFromImage') setParamsPyInt('SetRGB') - + c.find('FindFirstUnusedColour').type = 'void' c.find('FindFirstUnusedColour.r').pyInt = True c.find('FindFirstUnusedColour.g').pyInt = True c.find('FindFirstUnusedColour.b').pyInt = True @@ -78,6 +88,7 @@ def run(): c.find('GetMaskGreen').pyInt = True c.find('GetMaskBlue').pyInt = True + c.find('GetOrFindMaskColour').type = 'void' c.find('GetOrFindMaskColour.r').pyInt = True c.find('GetOrFindMaskColour.g').pyInt = True c.find('GetOrFindMaskColour.b').pyInt = True @@ -85,9 +96,153 @@ def run(): c.find('GetOrFindMaskColour.g').out = True c.find('GetOrFindMaskColour.b').out = True - + c.find('RGBValue.red').pyInt = True + c.find('RGBValue.green').pyInt = True + c.find('RGBValue.blue').pyInt = True + c.find('RGBValue.RGBValue.r').pyInt = True + c.find('RGBValue.RGBValue.g').pyInt = True + c.find('RGBValue.RGBValue.b').pyInt = True + + + c.addCppMethod('int', '__nonzero__', '()', 'return self->IsOk();') + + c.addPyMethod('ConvertToBitmap', '(self, depth=-1)', """\ + bmp = wx.Bitmap(self, depth) + return bmp + """) + c.addPyMethod('ConvertToMonoBitmap', '(self, red, green, blue)', """\ + mono = self.ConvertToMono( red, green, blue ) + bmp = wx.Bitmap( mono, 1 ) + return bmp + """) + + + c.addCppMethod('wxImage*', 'AdjustChannels', + '(double factor_red, double factor_green, double factor_blue, double factor_alpha=1.0)', + doc="""\n + AdjustChannels(factor_red, factor_green, factor_blue, factor_alpha=1.0)\n + This function muliplies all 4 channels (red, green, blue, alpha) with + a factor (around 1.0). Useful for gamma correction, colour correction + and to add a certain amount of transparency to a image (fade in fade + out effects). If factor_alpha is given but the original image has no + alpha channel then a alpha channel will be added. + """, + body="""\ + wxCHECK_MSG( self->Ok(), NULL, wxT("invalid image") ); + + wxImage* dest = new wxImage( self->GetWidth(), self->GetHeight(), false ); + wxCHECK_MSG( dest && dest->IsOk(), NULL, wxT("unable to create image") ); + + unsigned rgblen = 3 * self->GetWidth() * self->GetHeight(); + unsigned alphalen = self->GetWidth() * self->GetHeight(); + unsigned char* src_data = self->GetData(); + unsigned char* src_alpha = self->GetAlpha(); + unsigned char* dst_data = dest->GetData(); + unsigned char* dst_alpha = NULL; + + // adjust rgb + if ( factor_red == 1.0 && factor_green == 1.0 && factor_blue == 1.0) + { + // nothing to do for RGB + memcpy(dst_data, src_data, rgblen); + } + else + { + // rgb pixel for pixel + for ( unsigned i = 0; i < rgblen; i= i + 3 ) + { + dst_data[i] = (unsigned char) wxMin( 255, (int) (factor_red * src_data[i]) ); + dst_data[i + 1] = (unsigned char) wxMin( 255, (int) (factor_green * src_data[i + 1]) ); + dst_data[i + 2] = (unsigned char) wxMin( 255, (int) (factor_blue * src_data[i + 2]) ); + } + } + + // adjust the mask colour + if ( self->HasMask() ) + { + dest->SetMaskColour((unsigned char) wxMin( 255, (int) (factor_red * self->GetMaskRed() ) ), + (unsigned char) wxMin( 255, (int) (factor_green * self->GetMaskGreen() ) ), + (unsigned char) wxMin( 255, (int) (factor_blue * self->GetMaskBlue() ) ) ); + } + + // adjust the alpha channel + if ( src_alpha ) + { + // source image already has alpha information + dest->SetAlpha(); // create an empty alpha channel (not initialized) + dst_alpha = dest->GetAlpha(); + + wxCHECK_MSG( dst_alpha, NULL, wxT("unable to create alpha data") ); + + if ( factor_alpha == 1.0) + { + // no need to adjust + memcpy(dst_alpha, src_alpha, alphalen); + } + else + { + // alpha value for alpha value + for ( unsigned i = 0; i < alphalen; ++i ) + { + dst_alpha[i] = (unsigned char) wxMin( 255, (int) (factor_alpha * src_alpha[i]) ); + } + } + } + else if ( factor_alpha != 1.0 ) + { + // no alpha yet but we want to adjust -> create + dest->SetAlpha(); // create an empty alpha channel (not initialized) + dst_alpha = dest->GetAlpha(); + + wxCHECK_MSG( dst_alpha, NULL, wxT("unable to create alpha data") ); + + for ( unsigned i = 0; i < alphalen; ++i ) + { + dst_alpha[i] = (unsigned char) wxMin( 255, (int) (factor_alpha * 255) ); + } + } + + // do we have an alpha channel and a mask in the new image? + if ( dst_alpha && dest->HasMask() ) + { + // make the mask transparent honoring the alpha channel + const unsigned char mr = dest->GetMaskRed(); + const unsigned char mg = dest->GetMaskGreen(); + const unsigned char mb = dest->GetMaskBlue(); + + for ( unsigned i = 0; i < alphalen; ++i ) + { + int n = i * 3; + dst_alpha[i] = ( dst_data[n] == mr && dst_data[n + 1] == mg && dst_data[n + 2] == mb ) + ? wxIMAGE_ALPHA_TRANSPARENT + : dst_alpha[i]; + } + + // remove the mask now + dest->SetMask(false); + } + + return dest; + """) + + #%property(AlphaBuffer, GetAlphaBuffer, SetAlphaBuffer) + #%property(AlphaData, GetAlphaData, SetAlphaData) + #%property(Data, GetData, SetData) + #%property(DataBuffer, GetDataBuffer, SetDataBuffer) + + c.addProperty('Width GetWidth') + c.addProperty('Height GetHeight') + c.addProperty('MaskBlue GetMaskBlue') + c.addProperty('MaskGreen GetMaskGreen') + c.addProperty('MaskRed GetMaskRed') + c.addProperty('Type GetType SetType') + + + + #------------------------------------------------------- c = module.find('wxImageHistogram') setParamsPyInt('MakeKey') + c.find('FindFirstUnusedColour').type = 'void' c.find('FindFirstUnusedColour.r').pyInt = True c.find('FindFirstUnusedColour.g').pyInt = True c.find('FindFirstUnusedColour.b').pyInt = True @@ -99,6 +254,8 @@ def run(): c.find('FindFirstUnusedColour.b').out = True + #------------------------------------------------------- + module.find('wxIMAGE_ALPHA_TRANSPARENT').pyInt = True module.find('wxIMAGE_ALPHA_OPAQUE').pyInt = True diff --git a/unittests/test_image.py b/unittests/test_image.py new file mode 100644 index 00000000..aef2fb47 --- /dev/null +++ b/unittests/test_image.py @@ -0,0 +1,126 @@ +import imp_unittest, unittest +import wtc +import wx +import os + +pngFile = os.path.join(os.path.dirname(__file__), 'toucan.png') + +#--------------------------------------------------------------------------- + +class image_Tests(wtc.WidgetTestCase): + + def test_imageCtor1(self): + img = wx.Image() + self.assertTrue(not img.IsOk()) + img.Create(100,100) + self.assertTrue(img.IsOk()) + + def test_imageCtor2(self): + img = wx.Image(100,100) + self.assertTrue(img.IsOk()) + + def test_imageCtor3(self): + img = wx.Image(wx.Size(100,100)) + self.assertTrue(img.IsOk()) + img = wx.Image((100,100)) + self.assertTrue(img.IsOk()) + + def test_imageCtor4(self): + self.fail("data buffer support TBI") + import array + w = h = 10 + buf = array.array('B', '\0' * (w*h*3)) + img = wx.Image(w, h, buf, True) + self.assertTrue(img.IsOk()) + + def test_imageCtor5(self): + return + self.fail("data buffer support TBI") + import array + w = h = 10 + buf = array.array('B', '\0' * (w*h*3)) + alpha = array.array('B', '\0' * (w*h)) + img = wx.Image(w, h, buf, alpha, True) + self.assertTrue(img.IsOk()) + + def test_imageCtor6(self): + img = wx.Image(pngFile, wx.BITMAP_TYPE_PNG) + self.assertTrue(img.IsOk()) + + def test_imageCtor7(self): + img = wx.Image(pngFile, 'image/png') + self.assertTrue(img.IsOk()) + + def test_imageCtor8(self): + self.fail('stream support TBI') + data = open(pngFile, 'rb').read() + import StringIO + stream = StringIO.StringIO(data) + img = wx.Image(stream, wx.BITMAP_TYPE_PNG) + self.assertTrue(img.IsOk()) + + def test_imageCtor9(self): + return + self.fail('stream support TBI') + data = open(pngFile, 'rb').read() + import StringIO + stream = StringIO.StringIO(data) + img = wx.Image(stream, 'image/png') + self.assertTrue(img.IsOk()) + + + + def test_imageNestedClasses(self): + rgb = wx.Image.RGBValue(1,2,3) + self.assertEqual(rgb.red, 1) + self.assertEqual(rgb.green, 2) + self.assertEqual(rgb.blue, 3) + rgb.red = 4 + rgb.green = 5 + rgb.blue = 6 + + hsv = wx.Image.HSVValue(1.1, 1.2, 1.3) + self.assertEqual(hsv.hue, 1.1) + self.assertEqual(hsv.saturation, 1.2) + self.assertEqual(hsv.value, 1.3) + hsv.hue = 2.1 + hsv.saturation = 2.2 + hsv.value = 2.3 + + + def test_imageRGBHSV(self): + rgb = wx.Image.RGBValue(1,2,3) + hsv = wx.Image.RGBtoHSV(rgb) + rgb = wx.Image.HSVtoRGB(hsv) + self.assertEqual(rgb.red, 1) + self.assertEqual(rgb.green, 2) + self.assertEqual(rgb.blue, 3) + + + def test_imageProperties(self): + img = wx.Image(pngFile) + self.assertTrue(img.IsOk()) + img.Width + img.Height + img.MaskRed + img.MaskGreen + img.MaskBlue + img.Type + + + def test_imageMethodChain(self): + img = wx.Image(100,100).Rescale(75,75).Resize((100,100), (0,0), 40,60,80) + self.assertTrue(img.IsOk()) + + + def test_imageOtherStuff(self): + img = wx.Image(pngFile) + self.assertTrue(img.IsOk()) + r, g, b = img.FindFirstUnusedColour() + r, g, b = img.GetOrFindMaskColour() + +#--------------------------------------------------------------------------- + + +if __name__ == '__main__': + unittest.main()