Bug: need mark_dirty() within wx.lib.wxcairo.ImageSurfaceFromBitmap

3 views
Skip to first unread message

rocketman

unread,
May 16, 2012, 8:37:51 PM5/16/12
to wxPython-dev
I am extending wx.BitmapButton to include some custom drawing on the
bitmap using cairo and I stumbled across what appears to be a bug in
the function ImageSurfaceFromBitmap within the wx.lib.wxcairo module.

I believe that when creating a surface from a bitmap (within
ImageSurfaceFromBitmap) the resulting surface needs to get a
mark_dirty() call before returning.

The documentation comments:

"mark_dirty() tells cairo that drawing has been done to Surface using
means other than cairo, and that cairo should reread any cached areas.
Note that you must call flush() before doing such drawing."

In this case I do not think flush() is needed since the surface is
just created - but the mark_dirty() is still needed.

See the code below demonstrating:

Download smiley.png from: http://upload.wikimedia.org/wikipedia/en/6/6f/Smiley_Face.png

smiley_check.png should write back out correctly (oddly this works
since it must use the cache) and match smiley.png
smiley_fail.png will have the red nose only
smiley_succeed.png will have the face with the red nose


--------------------------------------------------------------------------
import cairo
import wx

from math import pi

FIX = False

# Extracted from wx.lib.wxcairo module
def ImageSurfaceFromBitmap(bitmap):
"""
Create an ImageSurface from a wx.Bitmap
"""
width, height = bitmap.GetSize()
if bitmap.HasAlpha():
format = cairo.FORMAT_ARGB32
fmt = wx.BitmapBufferFormat_ARGB32
else:
format = cairo.FORMAT_RGB24
fmt = wx.BitmapBufferFormat_RGB32

try:
stride = cairo.ImageSurface.format_stride_for_width(format,
width)
except AttributeError:
stride = width * 4

surface = cairo.ImageSurface(format, width, height)
bitmap.CopyToBuffer(surface.get_data(), fmt, stride)

if FIX:
surface.mark_dirty() # needed addition

return surface



def draw_red_nose(surface):
# copy surface into a new_surface
new_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 200, 200)
cr = cairo.Context(new_surface)
cr.set_source_surface(surface, 10, 10)
cr.paint()

# now draw a red nose
cr.set_source_rgb(255, 0, 0)
cr.arc(100, 100, 10, 0, 2 * pi)
cr.fill()

return new_surface


app = wx.PySimpleApp()
bitmap = wx.Bitmap('smiley.png')

surface = ImageSurfaceFromBitmap(bitmap)
surface.write_to_png('smiley_check.png') # this works
new_surface = draw_red_nose(surface)
new_surface.write_to_png('smiley_fail.png') # but this fails - no
smiley

# implement fix
FIX = True
surface = ImageSurfaceFromBitmap(bitmap)
new_surface = draw_red_nose(surface)
new_surface.write_to_png('smiley_succeed.png') # this works with fix

Robin Dunn

unread,
May 16, 2012, 10:15:42 PM5/16/12
to wxpyth...@googlegroups.com
On 5/16/12 5:37 PM, rocketman wrote:
> I am extending wx.BitmapButton to include some custom drawing on the
> bitmap using cairo and I stumbled across what appears to be a bug in
> the function ImageSurfaceFromBitmap within the wx.lib.wxcairo module.
>
> I believe that when creating a surface from a bitmap (within
> ImageSurfaceFromBitmap) the resulting surface needs to get a
> mark_dirty() call before returning.
>
> The documentation comments:
>
> "mark_dirty() tells cairo that drawing has been done to Surface using
> means other than cairo, and that cairo should reread any cached areas.
> Note that you must call flush() before doing such drawing."
>
> In this case I do not think flush() is needed since the surface is
> just created - but the mark_dirty() is still needed.

Thanks!

--
Robin Dunn
Software Craftsman
http://wxPython.org

Reply all
Reply to author
Forward
0 new messages