Add wx.Image.ConvertToRegion allowing to construct a region from an image without needing to make a bitmap first.

This commit is contained in:
Robin Dunn
2020-10-14 18:01:19 -07:00
parent f1a910db55
commit c5c28fd811
2 changed files with 90 additions and 6 deletions

View File

@@ -26,14 +26,17 @@ class TestFrame(wx.Frame):
self.Bind(wx.EVT_RIGHT_UP, self.OnExit)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.bmp = images.Vippi.GetBitmap()
img = images.Vippi.GetImage()
if img.HasAlpha():
img.ConvertAlphaToMask()
self.img = img
self.bmp = wx.Bitmap(img)
w, h = self.bmp.GetWidth(), self.bmp.GetHeight()
self.SetClientSize( (w, h) )
if wx.Platform != "__WXMAC__":
# wxMac clips the tooltip to the window shape, YUCK!!!
self.SetToolTip("Right-click to close the window\n"
"Double-click the image to set/unset the window shape")
self.SetToolTip("Right-click to close the window\n"
"Double-click the image to set/unset the window shape")
if wx.Platform == "__WXGTK__":
# wxGTK requires that the window be created before you can
@@ -50,9 +53,11 @@ class TestFrame(wx.Frame):
def SetWindowShape(self, *evt):
# Use the bitmap's mask to determine the region
r = wx.Region(self.bmp)
#r = wx.Region(self.bmp)
r = self.img.ConvertToRegion()
self.hasShape = self.SetShape(r)
def OnDoubleClick(self, evt):
if self.hasShape:
self.SetShape(wx.Region())

View File

@@ -496,6 +496,85 @@ def run():
c.addProperty('Type GetType SetType')
c.addCppMethod('wxRegion*', 'ConvertToRegion',
'(int R=-1, int G=-1, int B=-1, int tolerance=0)',
doc="""\
Create a :class:`wx.Region` where the transparent areas match the given RGB values.
If the RGB values are not given, then the image's mask colour
components will be used instead. If a non-zero tolerance is given
then the pixels that fall into the range of (R,G,B) to
(R+tolerance, G+tolerance, B+tolerance) will be considered to be
transparent.
If there are no pixels matching the transparent colours then the
region returned will match the image's full dimensions.
:param int `R`: The red component of the transparent colour.
:param int `G`: The red component of the transparent colour.
:param int `B`: The red component of the transparent colour.
:param int `tolerance`: Broadens the range of colours that will
be considered transparent.
:returns: a :class:`wx.Region` object.
""",
body="""\
wxRegion* region = new wxRegion();
unsigned char hiR, hiG, hiB;
if (R == -1) { R = self->GetMaskRed(); }
if (G == -1) { G = self->GetMaskGreen(); }
if (B == -1) { B = self->GetMaskBlue(); }
// Make sure nothing out of range was passed
R &= 0xFF;
G &= 0xFF;
B &= 0xFF;
hiR = (unsigned char)wxMin(0xFF, R + tolerance);
hiG = (unsigned char)wxMin(0xFF, G + tolerance);
hiB = (unsigned char)wxMin(0xFF, B + tolerance);
// Loop through the image row by row, pixel by pixel, building up
// rectangles to add to the region.
int width = self->GetWidth();
int height = self->GetHeight();
for (int y=0; y < height; y++)
{
wxRect rect;
rect.y = y;
rect.height = 1;
for (int x=0; x < width; x++)
{
// search for a continuous range of non-transparent pixels
int x0 = x;
while ( x < width)
{
unsigned char red = self->GetRed(x,y);
unsigned char grn = self->GetGreen(x,y);
unsigned char blu = self->GetBlue(x,y);
if (( red >= R && red <= hiR) &&
( grn >= G && grn <= hiG) &&
( blu >= B && blu <= hiB)) // It's transparent
break;
x++;
}
// Add the run of non-transparent pixels (if any) to the region
if (x > x0) {
rect.x = x0;
rect.width = x - x0;
region->Union(rect);
}
}
}
if (region->IsEmpty())
region->Union(0, 0, width, height);
return region;
""")
# For compatibility:
module.addPyFunction('EmptyImage', '(width=0, height=0, clear=True)',
deprecated="Use :class:`Image` instead.",