Cross-platform issues with wx.BrushFromBitmap

Hi folks,

I'm currently writing a cross-platform app for Windows XP (SP2), Linux (FC6), and Mac (10.4.9) using Python 2.5.1 and wxPython 2.8.3. Here is a short program segment that produces very different results on each of these systems. What I'm after is the ability to define my own fill pattern for dc.DrawRectangle() using a bitmap based on a PNG. Each system correctly draws a single bitmap that respects the transparent background of the bitmap. However, the stippled brush fill pattern only works the way I want on the Mac. On Windows the background is black and on Linux I get a monochrome (black on white) result. Here's a link to the PNG file I'm using (star.png):

http://www.famfamfam.com/lab/icons/silk/

Any small PNG file with a transparent background should work to illustrate the problem. Cross-hatching (commented out below) works fine on all platforms too. Any ideas?

Thanks,
Dan

#! /usr/bin/env python

import os
import sys
import wx

class MyFrame(wx.Frame):
  def __init__(self, parent=None, id=-1, title='My Frame',
        pos=wx.DefaultPosition, size=(300,300)):
    
    wx.Frame.__init__(self, parent, id, title, pos, size)
    
    self.stipple = wx.Bitmap(sys.path[0] + os.sep + 'star.png', wx.BITMAP_TYPE_PNG)
    
    self.InitBuffer()

    self.Bind(wx.EVT_SIZE, self.OnSize)
    self.Bind(wx.EVT_PAINT, self.OnPaint)
    
  def InitBuffer(self):
    (w, h) = self.GetClientSize()
    self.buffer = wx.EmptyBitmap(w, h)
    dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
    self.Draw(dc)
    
  def Draw(self, dc):
    dc.SetBackground(wx.Brush('blue', wx.SOLID))
    dc.Clear()

    dc.SetPen(wx.Pen('yellow', 2, wx.SOLID))
    
    brush = wx.BrushFromBitmap(self.stipple)
    
    #dc.SetBrush(wx.Brush('yellow', wx.CROSSDIAG_HATCH))
    dc.SetBrush(brush)
    
    dc.DrawBitmap(self.stipple, 150, 25)
    dc.DrawRectangle(50, 50, 200, 200)

  def OnSize(self, event):
    self.InitBuffer()
    
  def OnPaint(self, event):
    dc = wx.BufferedPaintDC(self, self.buffer)
  
if __name__ == '__main__':
  app = wx.PySimpleApp()
  frame = MyFrame()
  frame.Show()
  app.MainLoop()

···

--
Dr. Daniel B. Koch
Oak Ridge National Lab
http://www.ornl.gov/sci/gist/bios/bio_koch.html
(865) 241-9096

Daniel B. Koch wrote:

Hi folks,

I'm currently writing a cross-platform app for Windows XP (SP2), Linux (FC6), and Mac (10.4.9) using Python 2.5.1 and wxPython 2.8.3. Here is a short program segment that produces very different results on each of these systems. What I'm after is the ability to define my own fill pattern for dc.DrawRectangle() using a bitmap based on a PNG. Each system correctly draws a single bitmap that respects the transparent background of the bitmap. However, the stippled brush fill pattern only works the way I want on the Mac. On Windows the background is black and on Linux I get a monochrome (black on white) result.

First, I expect that the native APIs are not set up to handle an alpha channel for the stipple bitmaps, so if I convert the alpha to a mask then wxMSW and wxGTK behave identically. However, believe it or not, I think that wxMac is the one that is incorrect here. My understanding of stipples is that it is supposed to be (at least historically) monochrome, you are either setting pixels to the brush's color or not based on the bits in the stipple.

If you want to fill with a bitmap you can draw them yourself of course, using a clipping region if you need to clip the drawing to a specific area.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

Daniel B. Koch wrote:

Hi folks,

I'm currently writing a cross-platform app for Windows XP (SP2), Linux (FC6), and Mac (10.4.9) using Python 2.5.1 and wxPython 2.8.3. Here is a short program segment that produces very different results on each of these systems. What I'm after is the ability to define my own fill pattern for dc.DrawRectangle() using a bitmap based on a PNG. Each system correctly draws a single bitmap that respects the transparent background of the bitmap. However, the stippled brush fill pattern only works the way I want on the Mac. On Windows the background is black and on Linux I get a monochrome (black on white) result.

First, I expect that the native APIs are not set up to handle an alpha channel for the stipple bitmaps, so if I convert the alpha to a mask then wxMSW and wxGTK behave identically. However, believe it or not, I think that wxMac is the one that is incorrect here. My understanding of stipples is that it is supposed to be (at least historically) monochrome, you are either setting pixels to the brush's color or not based on the bits in the stipple.

I was 3/4 right. MSW and GTK don't support alpha in stipples, and if the bitmap has a mask then it does monochrome stippling using the masked and unmasked pixels. However it is possible to do color stipples, the image just needs to not have an alpha channel. If your bitmap does have alpha then you can preblend it into the background color making a new bitmap, like this:

         bmp = wx.Bitmap(sys.path[0] + os.sep + 'star.png', wx.BITMAP_TYPE_PNG)
         self.stipple = wx.EmptyBitmap(*bmp.GetSize())
         dc = wx.MemoryDC(self.stipple)
         dc.SetBackground(wx.Brush('blue'))
         dc.Clear()
         dc.DrawBitmap(bmp, 0, 0)

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!