bitmap resource problem(?)

Hi!

This is my first attempt to use wx seriously, and I came upon a problem which is due to incorrect use, so help would be appreciated!

I am using wxPython 6.1 with Python 2.4.1.

I have a Python application that produces a large number of HTML pages per run (in the hundreds). The pages may include some graphics which, up to now, used to be produced by Java applets and Javascript from instruction in the pages.
In an effort to reduce loading time, I have decided to convert some of these graphics to prepared bit maps on disk files (200-300 JPEG files per run over typical data).
For various reasons, I have selected wxPython as the graphics library (although the application runs in DOS and involves no GUI, for the moment).
The application initializes a singleton wxApp (but redirects system output back to app.saveStdio). For drawing, the application
uses a wx.MemoryDc over a wx.EmptyBitmap. Then comes vector graphics part. When the drawing is done, the image is saved to a JPEG file, by sending a message to a wx.ImageFromBitmap created inline.

The graphics come out fine, however, there seems to be a problem with MS-Windows resources. After generating a large number of bitmaps, e.g., when iterating over producing the same lot, (say, some 400 drawings),
the program crashes with an error like this one:

*** _core.pyc 2596 in ImageFromBitmap(
*** PyAssertionError: "C++ assertion "wxAssertFailure" failed in ..\..\src\msw\dib.cpp(152): wxDIB::Create(): invalid bitmap"

The crash is consistent and will repeat at the same spot in each run, depending on the input.
There is nothing wrong about the specific bitmap, because it came out fine in the previous iteration.
The problem does not seem to be related to memory. It occurs on both a 1GB machine and a 256MB machine (with the same data), though not at the same places.

Suspecting a graphic resource allocation problem, I have decided to get rid of the image and DC immediately after the file is written.
First, I get rid of the renderer object that was the only other user of the DC. Then I ask the DC to SelectObject(wx.NullBitmap). Then I ask the image to Destroy(), get rid of the image and the dc, in that order. I believe this is the correct sequence to do it, according to the wx library documentation.
However, the message Destroy() to the image makes the Python interpreter itself crash with a core dump.

My question is: What is the correct way to get rid of all the graphic resources in time, so that the program may produce as many bitmap files as necessary without ever crashing.

I must have a solution that comes from the very application. Since the application is deployed on the client's machine, re-configuring MS-Windows is out of the question.

    Avner.

I'm not sure I can be much help, but I do have a suggestion or two to try:

avnerben@012.net.il wrote:

For drawing, the application
uses a wx.MemoryDc over a wx.EmptyBitmap. Then comes vector graphics part. When the drawing is done, the image is saved to a JPEG file, by sending a message to a wx.ImageFromBitmap created inline.

You don't need to do that. You can just use:

wx.Bitmap.SaveFile(filename, wx.BITMAP_TYPE_JPEG)

It may well do the same this under the hood, but it's cleaner in your code.

The graphics come out fine, however, there seems to be a problem with MS-Windows resources.

You do want to make suer you're not keeping a wx.Bitmap or wx.DC around for each image. In fact, you should be able to re-use the same one for all your image drawing, something like this:

BM = wx.EmptyBitmap(width, height)
DC = wx.MemoryDC()
DC.SelectObject(BM)

for i in WhateverList:
     DC.SetBackground(ABrush)
     DC.Clear()

     #Do Your Drawing here

     BM.SaveFile(filename, wx.BITMAP_TYPE_JPEG)

That should let you make any number of jpegs without ever creating more than one Bitmap and DC.

Suspecting a graphic resource allocation problem, I have decided to get rid of the image and DC immediately after the file is written.
First, I get rid of the renderer object that was the only other user of the DC. Then I ask the DC to SelectObject(wx.NullBitmap). Then I ask the image to Destroy()

This could be a problem. In general, you don't want to call the wx Destroy() function, but rather just let Python's reference counting take care of things for you. so, use del, or just let the object fall out of scope.

by the way, posting a minimal, but complete, example as an attachment can make it easier for us to figure out what you can do, as well as test it on other systems.

-good luck, Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

thanks,

I'll give these a try.

I am reluctant to reuse the same image and DC, Since the pictures are in different Sizes. I had bad experience before with resizing bitmaps - the graphics did not come out right.

    Avner.

Chris Barker wrote:

I'm not sure I can be much help, but I do have a suggestion or two to try:

For drawing, the application
uses a wx.MemoryDc over a wx.EmptyBitmap. Then comes vector graphics part. When the drawing is done, the image is saved to a JPEG file, by sending a message to a wx.ImageFromBitmap created inline.

You don't need to do that. You can just use:

wx.Bitmap.SaveFile(filename, wx.BITMAP_TYPE_JPEG)

It may well do the same this under the hood, but it's cleaner in your code.

The graphics come out fine, however, there seems to be a problem with MS-Windows resources.

You do want to make suer you're not keeping a wx.Bitmap or wx.DC around for each image. In fact, you should be able to re-use the same one for all your image drawing, something like this:

BM = wx.EmptyBitmap(width, height)
DC = wx.MemoryDC()
DC.SelectObject(BM)

for i in WhateverList:
    DC.SetBackground(ABrush)
    DC.Clear()

    #Do Your Drawing here

    BM.SaveFile(filename, wx.BITMAP_TYPE_JPEG)

That should let you make any number of jpegs without ever creating more than one Bitmap and DC.

Suspecting a graphic resource allocation problem, I have decided to get rid of the image and DC immediately after the file is written.
First, I get rid of the renderer object that was the only other user of the DC. Then I ask the DC to SelectObject(wx.NullBitmap). Then I ask the image to Destroy()

This could be a problem. In general, you don't want to call the wx Destroy() function, but rather just let Python's reference counting take care of things for you. so, use del, or just let the object fall out of scope.

by the way, posting a minimal, but complete, example as an attachment can make it easier for us to figure out what you can do, as well as test it on other systems.

-good luck, Chris

\

···

avnerben@012.net.il wrote:

avnerben@012.net.il wrote:

I am reluctant to reuse the same image and DC, Since the pictures are in different Sizes. I had bad experience before with resizing bitmaps - the graphics did not come out right.

That's a little more complicated. There is a wx.Bitmap.SetSize() method, but I've never tried it. I'd give it a shot. You could also make a new bitmap each time, but still use the same DC.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

Chris Barker wrote:

I'm not sure I can be much help, but I do have a suggestion or two to try:

For drawing, the application
uses a wx.MemoryDc over a wx.EmptyBitmap. Then comes vector graphics part. When the drawing is done, the image is saved to a JPEG file, by sending a message to a wx.ImageFromBitmap created inline.

You don't need to do that. You can just use:

wx.Bitmap.SaveFile(filename, wx.BITMAP_TYPE_JPEG)

It may well do the same this under the hood, but it's cleaner in your code.

Ok, I did that and it delayed crash for a while. (But it does come eventually.)

The graphics come out fine, however, there seems to be a problem with MS-Windows resources.

You do want to make suer you're not keeping a wx.Bitmap or wx.DC around for each image. In fact, you should be able to re-use the same one for all your image drawing, something like this:

BM = wx.EmptyBitmap(width, height)
DC = wx.MemoryDC()
DC.SelectObject(BM)

for i in WhateverList:
    DC.SetBackground(ABrush)
    DC.Clear()

    #Do Your Drawing here

    BM.SaveFile(filename, wx.BITMAP_TYPE_JPEG)

That should let you make any number of jpegs without ever creating more than one Bitmap and DC.

Reusing the DC does not change the Situation.

Reusing the bitmap won't do. Each Bitmap is of different size. Although Bitmap has settHeight() and SetWidth() methods, They do not seem to do anything useful!

Suspecting a graphic resource allocation problem, I have decided to get rid of the image and DC immediately after the file is written.
First, I get rid of the renderer object that was the only other user of the DC. Then I ask the DC to SelectObject(wx.NullBitmap). Then I ask the image to Destroy()

This could be a problem. In general, you don't want to call the wx Destroy() function, but rather just let Python's reference counting take care of things for you. so, use del, or just let the object fall out of scope.

by the way, posting a minimal, but complete, example as an attachment can make it easier for us to figure out what you can do, as well as test it on other systems.

-good luck, Chris

Thanks for the advice!

    Avner.

···

avnerben@012.net.il wrote: