Hi Robin,
>>>> The line of code that fails is:
>>>>
>>>> # Load the image
>>>> self.bgImage = wx.Image(self.obj.image_filename)
>>>>
>>>> At the moment, I get a console message that says:
>>>>
>>>> Application transferred too few scanlines
>>>>
>>>> (I have no idea where this message comes from) and self.bgImage.IsOk()
>>>> returns false.
>>> It looks like it is coming from libjpeg. See
>>> wxWidgets/src/jpeg/jerror.h line #116. It's used in the functions
>>> jpeg_finish_compress and jpeg_finish_decompress, with code like this:
>>>
>>> if (cinfo->next_scanline< cinfo->image_height)
>>> ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
>>>
>>> My guess is that it's probably a memory or resource issue, and that the
>>> actual problem is happening some time before the lines of code above,
>>> but that it is manifesting as not enough image data being sent to those
>>> functions so that is where it is caught.
>>
>> Thanks for all of your help. I've finally resolved the issue.
>>
>> It turns out that my wx.Image call was the problem. I wasn't Destroying
>> it properly. Since it was defined in the context of a wx.Frame, I
>> assumed it would be destroyed when the frame was destroyed, but
>
> Was it holding a reference to the image, something like "self.img =
> wx.Image(...)" or was it just used as a local variable like "img =
> wx.Image(...)" ?
It was (and is) a self.img reference, as I reuse the image in a couple
of methods in the object.
For context, this part of the application is for doing analytic mark-up
of still images using a FloatCanvas. If the user chooses to clear or
temporarily hide some of their mark-up, I need to redraw, and I reuse
self.img during that process.
For the reports, I open the markup window without showing it, load the
image from the file and the mark-up from the database, extract the
marked-up image to put into the report, and close the markup window
without ever showing it.
In terms of avoiding memory leaks, am I better off retaining the
self.img reference, or am I better off just remembering the file name
and creating a new local img when I need one within the markup window?
Okay.... I mostly understand what you're saying, I think. Maybe. But I
haven't got a clue how to DO this "breaking the cycles yourself" of
which you speak.
Basically, I open the SnapshotWindow (a wx.Frame that houses some
toolbars and a FloatCanvas object named canvas, and which loads an image
from a file) without showing it, draw the markup (using _DrawObjects),
and copy the image to tmpBMP, then I close and destroy the Snapshot Window.
Here's the critical code:
# Open a HIDDEN Snapshot Window
tmpSnapshotWindow = SnapshotWindow.SnapshotWindow(menuWindow, -1,
tmpObj.id, tmpObj,
showWindow=False)
# Reset the Bounding Box to avoid NaN problems
tmpSnapshotWindow.canvas._ResetBoundingBox()
# Get the image's Bounding Box
box = tmpSnapshotWindow.canvas.BoundingBox
# Create an empty Bitmap the size of the image
tmpBMP = wx.EmptyBitmap(tmpSnapshotWindow.canvas.GetSize()[0],
tmpSnapshotWindow.canvas.GetSize()[1])
# Get the MemoryDC for the empty bitmap
tempDC = wx.MemoryDC(tmpBMP)
# Set the bitmap's background colour to WHITE
tempDC.SetBackground(wx.Brush("white"))
tempDC.Clear()
# Create a ClientDC for the hidden Shapshot Window
tempDC2 = wx.ClientDC(tmpSnapshotWindow)
# Create another MemoryDC (although I'm not sure why!)
tempDC3 = wx.MemoryDC()
# Get the image from the hidden Snapshot Window's Canvas and
# put it in the Device Contexts we just created
tmpSnapshotWindow.canvas._DrawObjects(tempDC,
tmpSnapshotWindow.canvas._DrawList,
tempDC2, box, tempDC3)
# Close the hidden Snapshot Window
tmpSnapshotWindow.Close()
# Explicitly Delete the Temporary Snapshot Window
tmpSnapshotWindow.Destroy()
To the extent that I understand this, I think I've made a copy of image
drawn on the SnapshotWindow's canvas and don't think I retain any
reference to that canvas or to the wx.Image object used inside the
SnapshotWindow object to populate the FloatCanvas object. But to be
honest, I'm a bit fuzzy about device contexts and exactly how the image
I need ends up in tmpBMP here. I have no idea why 3 device contexts
seem to come into play, for example.
So if Destroy() isn't going to do what I need here, what do I do? Do I
need to explicitly call del(tmpBMP) or del(tmpSnapshotWindow)? Is there
something more I need to do?
Sorry for my ignorance here, but I'm a psychologist by training and am
self-taught with computers, and there are holes in my understanding of
some of this.
Thanks, as always, for your help.
David