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
This commit is contained in:
Robin Dunn
2011-10-14 06:40:40 +00:00
parent 4924ed5ccd
commit 640f22a259
2 changed files with 292 additions and 9 deletions

View File

@@ -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

126
unittests/test_image.py Normal file
View File

@@ -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()