DC+Bitmap Is it a bug?

"""
The idea is render a bitmap using memoryDC and keet it.
Later draw this bitmap on another memoryDC operation.
Problem is that bitmap is loosing it's transparency.
The code below will show you the problem
"""

# -*- coding: iso-8859-1 -*-#
#!/usr/bin/env python2.4

import wx

class DemoApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers() # called so a PNG can be saved

        # Render a bitmap using MemoryDC.
        # We are drawing an ellipse thus we need a bitmap with
        # transparency. We are going to keep this bitmap for later...
        width, height = 100, 50
        size = width, height
        colorBitmap = wx.EmptyBitmapRGBA(size[0], size[1], 0, 0, 0,
0)
        mdc = wx.MemoryDC(colorBitmap)
        mdc.SetPen(wx.Pen("white", 1))
        mdc.SetBrush(wx.Brush("red"))
        mdc.SetDeviceOrigin(0, 0)
        mdc.DrawEllipse(0, 0, width, height)
        # Select the Bitmap out of the memory DC
        # by selecting a new uninitialized Bitmap
        mdc.SelectObject(wx.NullBitmap)
        del mdc

        # Create another bitmap using memoryDC and
        # draw the bitmap created above.
        newBitmap = wx.EmptyBitmap(*size)
        mdc = wx.MemoryDC()
        mdc.SelectObject(newBitmap)
        # Draw bitmap with a gray background
        mdc.SetBackground(wx.Brush("gray"))
        mdc.Clear() # make sure you clear the bitmap!
        mdc.DrawBitmap(colorBitmap, 0, 0)
        # Select the Bitmap out of the memory DC
        # by selecting a new uninitialized Bitmap
        mdc.SelectObject(wx.NullBitmap)
        del mdc

        # BUG:
        # Save file and you can see that ellipse is saved
        # with some level of transparency. It's not complete red.
        img = newBitmap.ConvertToImage()
        fileName = "memdc.png"
        img.SaveFile(fileName, wx.BITMAP_TYPE_PNG)

        return True

if __name__ == "__main__":
    print "about to initialize the app"
    app = DemoApp(0)
    app.MainLoop()

King wrote:

Problem is that bitmap is loosing it's transparency.
The code below will show you the problem

It seems to work fine on my OS-X box -- what OS and wx version number are you using?

import wx

class DemoApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers() # called so a PNG can be saved

        # Render a bitmap using MemoryDC.
        # We are drawing an ellipse thus we need a bitmap with
        # transparency. We are going to keep this bitmap for later...
        width, height = 100, 50
        size = width, height
        colorBitmap = wx.EmptyBitmapRGBA(size[0], size[1], 0, 0, 0,
0)
        mdc = wx.MemoryDC(colorBitmap)
        mdc.SetPen(wx.Pen("white", 1))
        mdc.SetBrush(wx.Brush("red"))
        mdc.SetDeviceOrigin(0, 0)
        mdc.DrawEllipse(0, 0, width, height)
        # Select the Bitmap out of the memory DC
        # by selecting a new uninitialized Bitmap
        mdc.SelectObject(wx.NullBitmap)
        del mdc

        # Create another bitmap using memoryDC and
        # draw the bitmap created above.
        newBitmap = wx.EmptyBitmap(*size)

don't you want a wx.EmptyBitmapRGBA here, too?

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

King wrote:

"""
The idea is render a bitmap using memoryDC and keet it.
Later draw this bitmap on another memoryDC operation.
Problem is that bitmap is loosing it's transparency.

Another thought -- you may want to use a GraphicsContext instead -- DCs originally didn't support transparency at all, so maybe they don't work as well for that.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Another thought -- you may want to use a GraphicsContext instead -- DCs
originally didn't support transparency at all, so maybe they don't work
as well for that.

I am on Win XP 32, Python 2.6.2, wxPython 2.8.10.1.
Yes, on GraphicsContext it's working fine.

The big question is that is it a bug on ms-win or it doesn't work with
DCs?
Even in my case the second bitmap is first filled with gray color and
ellipse is drawn later.
If DCs doesn't support transparency then I would have get an image
with black background & red
colour ellipse on top of it. Some thing is fishy and I have no idea :-
(

Chris, I would like to ask you few questions about DCs.

mdc = wx.MemoryDC(bmp)
gc = wx.GraphicContext.Create(mdc)

Drawing on gc is much slower then drawing on mdc. Is it the
transparency and anti-aliasing of gc or anything else?

How to render/draw anti-aliased fonts? Specially when your application
has an interactive scaling/zooming. Rendering
an offline bitmap using PIL or cairo and drawing it later is slower.

Prashant

On Windows the DCs are totally unaware of the alpha channel in the target bitmap they are drawing upon, so they don't do anything to modify it while drawing.

···

On 12/15/09 3:59 AM, King wrote:

"""
The idea is render a bitmap using memoryDC and keet it.
Later draw this bitmap on another memoryDC operation.
Problem is that bitmap is loosing it's transparency.
The code below will show you the problem
"""

--
Robin Dunn
Software Craftsman

mdc = wx.MemoryDC(bmp)
gc = wx.GraphicContext.Create(mdc)

Drawing on gc is much slower then drawing on mdc. Is it the
transparency and anti-aliasing of gc or anything else?

It's because on Windows it is using the MS GDI+ library for the backend, which is quite slow compared to DCs.

How to render/draw anti-aliased fonts? Specially when your application
has an interactive scaling/zooming.

Very similar to doing it on a DC. Set the font and use DrawText.

···

On 12/15/09 9:36 AM, King wrote:

--
Robin Dunn
Software Craftsman

"""
Here is the new test. The code below generate a bitmap by rendering a
text using
GraphicsContext and later bitmap is used by another dc operation to
save it. Every
thing is working fine and no problem in transparency.
How ever if you change the line in generation part:
ctx = wx.GraphicsContext.Create(mdc)#Cairo.GraphicsContext.Create(mdc)
to
ctx = Cairo.GraphicsContext.Create(mdc)
the bit "text.png" is coming out with transparency but while reading
it back
using:
mdc.DrawBitmap(colorBitmap, 0, 0)
again the I am facing the some transparency problem.

May be cairo's DrawBimap function is not able to read properly or some
explanation
is required here.

"""
# -*- coding: iso-8859-1 -*-#
#!/usr/bin/env python2.4

import wx
import wx.lib.graphics as Cairo

class DemoApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers() # called so a PNG can be saved
        font = wx.FFont(9, wx.SWISS, wx.FONTFLAG_BOLD, "Lucid
Console")
        # Render a bitmap using MemoryDC.
        width, height = 100, 100
        size = width, height
        colorBitmap = wx.EmptyBitmapRGBA(size[0]+1, size[1]+1, 0, 0,
0, 0)
        mdc = wx.MemoryDC(colorBitmap)
        ctx = wx.GraphicsContext.Create(mdc)
#Cairo.GraphicsContext.Create(mdc)
        ctx.SetFont(font, "blue")
        ctx.DrawText("wxPython Rocks!!!", 0, 45)
        mdc.SelectObject(wx.NullBitmap)
        del mdc
        colorBitmap.SaveFile("text.png", wx.BITMAP_TYPE_PNG)

        # Create another bitmap using memoryDC and
        # draw the bitmap created above.
        newBitmap = wx.EmptyBitmapRGBA(size[0]+1, size[1]+1, 0, 0, 0,
0)
        mdc = wx.MemoryDC(newBitmap)
        mdc.SetBackground(wx.Brush("gray"))
        mdc.Clear() # make sure you clear the bitmap!
        mdc.DrawBitmap(colorBitmap, 0, 0)
        mdc.SelectObject(wx.NullBitmap)
        del mdc
        newBitmap.SaveFile("memdc.png", wx.BITMAP_TYPE_PNG)

        return True

if __name__ == "__main__":
    print "about to initialize the app"
    app = DemoApp(0)
    app.MainLoop()

My guess is that Cairo is having some of the same problems with the alpha-ignorant Windows DC that wx has had to deal with. If you avoid using the wx.MemoryDC and do a little Cairo specfic things then it does what I think it is you are wanting:

import wx.lib.wxcairo as wxcairo

         colorBitmap = wx.EmptyBitmapRGBA(size[0]+1, size[1]+1, 0, 0, 0, 0)
         surface = wxcairo.ImageSurfaceFromBitmap(colorBitmap)
         ctx = Cairo.GraphicsContext.CreateFromSurface(surface)

         ctx.SetFont(font, "blue")
         ctx.DrawText("wxPython Rocks!!!", 0, 45)
         del ctx
         colorBitmap = wxcairo.BitmapFromImageSurface(surface)
         colorBitmap.SaveFile("text.png", wx.BITMAP_TYPE_PNG)

         # Create another bitmap using memoryDC and
         # draw the bitmap created above.
         newBitmap = wx.EmptyBitmap(size[0]+1, size[1]+1)
         mdc = wx.MemoryDC(newBitmap)
         mdc.SetBackground(wx.Brush("light grey"))
         mdc.Clear() # make sure you clear the bitmap!
         mdc.DrawBitmap(colorBitmap, 0, 0, True)
         mdc.SelectObject(wx.NullBitmap)
         del mdc
         newBitmap.SaveFile("memdc.png", wx.BITMAP_TYPE_PNG)

···

On 12/16/09 11:17 PM, King wrote:

"""
Here is the new test. The code below generate a bitmap by rendering a
text using
GraphicsContext and later bitmap is used by another dc operation to
save it. Every
thing is working fine and no problem in transparency.
How ever if you change the line in generation part:
ctx = wx.GraphicsContext.Create(mdc)#Cairo.GraphicsContext.Create(mdc)
to
ctx = Cairo.GraphicsContext.Create(mdc)
the bit "text.png" is coming out with transparency but while reading
it back
using:
mdc.DrawBitmap(colorBitmap, 0, 0)
again the I am facing the some transparency problem.

May be cairo's DrawBimap function is not able to read properly or some
explanation
is required here.

--
Robin Dunn
Software Craftsman

After all those discussions regarding DCs in various posts my
application is running fine on MS-Win.
As I said I have written is custom object oriented scene graph where
you two options for rendering.
wx.GraphicsContext and Cairo. Both are working fine on Ms-Win.

Now I started to test my app on Linux and none of the rendering method
is working properly. Cairo is badly crashing the
application. See here:
http://groups.google.com/group/wxpython-users/browse_thread/thread/89d0b0054eb8d1e4/6730a4f916b5c5cf#6730a4f916b5c5cf

and again bitmap transparency issue has risen. I am rendering off-line
bitmaps and then drawing them later. The alpha(transparency) is
replaced by pure black color in the bitmap. Here is code that I using
to draw a bitmap

import wx

class DemoApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers() # called so a PNG can be saved
        font = wx.FFont(9, wx.SWISS, wx.FONTFLAG_BOLD, "LucidConsole")
        # Render a bitmap using MemoryDC.
        width, height = 100, 100
        size = width, height
        colorBitmap = wx.EmptyBitmapRGBA(size[0]+1, size[1]+1, 0, 0,
0, 0)
        mdc = wx.MemoryDC(colorBitmap)
        ctx = wx.GraphicsContext.Create(mdc)
        ctx.SetFont(font, "blue")
        ctx.DrawText("wxPython Rocks!!!", 0, 45)
        ctx.SetBrush(wx.Brush("red"))
        ctx.DrawRectangle(10,10,25,25)
        # Select the Bitmap out of the memory DC by selecting a new
        # uninitialized Bitmap
        mdc.SelectObject(wx.NullBitmap)
        del mdc
        # Save file
        colorBitmap.SaveFile("text.png", wx.BITMAP_TYPE_PNG)
        return True

if __name__ == "__main__":
    print "about to initialize the app"
    app = DemoApp(0)
    app.MainLoop()

The bitmap is coming empty and instead of wx.EmptyBitmapRGBA if you
use wx.EmptyBitmap, bitmap is coming out with
a text and a red colour rectangle in it but also some garbage is
pixels is coming out.

I must find a solution for either wx.GraphicsContext or Cairo on Linux
or I am f|<ed.....

Thanks

Prashant

···

#####################################
Operating System: Linux 2.6.31-14-generic i686
Python Version: 2.6.4rc2 (r264rc2:75497, Oct 20 2009, 02:55:11)
[GCC 4.4.1]
wxPython Version: 2.8.10.1 (gtk2-unicode)
wxPython Info: (__WXGTK__, wxGTK, unicode, gtk2, wx-assertions-off,
SWIG-1.3.29)
Python Encoding: Default=UTF-8 File=UTF-8
wxPython Encoding: utf-8
System Architecture: 32bit i686
Byte order: little
Frozen: False
#####################################