pythonwxpython

Transparent background PNG in wxpython


Currently using WXpython creating a chess puzzle game and I'm trying to display 2 images, one on top of the other.

The issue is, despite the original image of the white pawn in my files having a transparent background, all the transparent pixels appear to be converted to white and block the image displayed behind.

I don't want to just create one image of the pieces on the board, as that would be very tedious.

Is there anyway i could make the background if the image transparent in wxpython?

boardIMG = "chessboard.PNG"
        self.board_img = wx.Image(boardIMG, wx.BITMAP_TYPE_PNG).Rescale(500,500).ConvertToBitmap()
        wx.StaticBitmap(self, -1, self.board_img, (0, 0), (self.board_img.GetWidth(), self.board_img.GetHeight()))

        WpawnIMG = "Wpawn.PNG"
        self.Wpawn_img = wx.Image(WpawnIMG, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
        wx.StaticBitmap(self, -1, self.Wpawn_img, (0,0), (self.Wpawn_img.GetWidth(), self.Wpawn_img.GetHeight()))

I have tried using python pillow to change pixel colors, using EVT_PAINT and mask as i have looked at similar issues on here, however have not found someone with the same issue.


Solution

  • The transparency support of wxPython's StaticBitmap control seems to be platform-dependent. Using more or less your exact code and these two images I got from Wikipedia:

    Chess boardWhite pawn

    import wx
    class MainWindow(wx.Frame):
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(500, 500))
            
            boardIMG = "chessboard.png"
            self.board_img = wx.Image(boardIMG, wx.BITMAP_TYPE_PNG).Rescale(500,500).ConvertToBitmap()
            wx.StaticBitmap(self, -1, self.board_img, (0, 0), (self.board_img.GetWidth(), self.board_img.GetHeight()))
    
            WpawnIMG = "whitepawn.png"
            self.Wpawn_img = wx.Image(WpawnIMG, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
            wx.StaticBitmap(self, -1, self.Wpawn_img, (0,0), (self.Wpawn_img.GetWidth(), self.Wpawn_img.GetHeight()))
    
    app = wx.App()
    frame = MainWindow(None, -1, "Window")
    frame.Show(1)
    app.MainLoop()
    

    I got the following results on Linux and Windows, respectively:

    Linux, transparent Windows, non-transparent

    An easy way to make it work on Windows as well is to handle OnPaint as follows:

    import wx
    class MainWindow(wx.Frame):
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(500, 500))
            
            boardIMG = "chessboard.png"
            self.board_img = wx.Image(boardIMG, wx.BITMAP_TYPE_PNG).Rescale(500,500).ConvertToBitmap()
            
            WpawnIMG = "whitepawn.png"
            self.Wpawn_img = wx.Bitmap(WpawnIMG) # can just use instead of the line below
            #self.Wpawn_img = wx.Image(WpawnIMG, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
            
            self.Bind(wx.EVT_PAINT, self.OnPaint)
    
        def OnPaint(self, evt):
            dc = wx.PaintDC(self)
    
            # draw the board first
            dc.DrawBitmap(self.board_img, 0, 0)
    
            # then the pieces
            for i in range(3):
                # image, horizontal pos, vertical pos
                dc.DrawBitmap(self.Wpawn_img, i * 150, 0)
    
    app = wx.App()
    frame = MainWindow(None, -1, "Window")
    frame.Show(1)
    app.MainLoop()
    

    Cross-platform with OnPaint

    Update the screen after updating their coordinates, and you'll have it not so much more complex than with StaticBitmap controls.