Josiah Carlson wrote:
Ultimately, if a user wants to use a buffer without copying, one should
be sure that the buffer cannot be moved in memory by design (string) or
by convention.
To wrap this up even more, and to make sure I get it... (is the OP even paying attention anymore?).
The buffer object itself does not manage memory, it is a container for a pointer. Which ever object first allocates the memory that the buffer is using is responsible for deleting it.
In the OP's case, I think the goal was to create the data for a wxImage in a C/C++ extension, then have a wxImage use it. One option is to use the wxWidgets C++ API to create a wxImage, then use the wxPython Swig stuff to wrap it. This means that the extension would have to be compiled against the right version of wxWidgets, and use all the right SWIG stuff.
The alternative is for the OP to create a buffer object that points to the data, and just pass that in to wx.Image.SetDataBuffer, all in Python, thus making sure that the object that manges the data stays around as long as the wx.Image does.
This is also relevant to the Matplotlib wx wrappers, which now need to be compiled against wx to get optimized passing of data form the Agg buffer to wxImage. I think we could use this technique instead, and then it's be easier to build MPL, and have it work with multiple versions of wx.
I've also used this to create a wx.Image from the data from a GDAL (geo-referenced raster maps) image. I had been creating a string from the data, then a wx.Image from the string, which really was one copy too many. Now I populate the wx.Image with SetDataBuffer, and make sure I keep a reference to the string around.
Which brings me to the next point:
I've written a tiny little factory function that creates a wx.Image with the data from a buffer, with a reference to the buffer. That way, the buffer object won't get deleted until after the wx.Image is deleted. Of course, as Josiah has made clear, that doesn't guarantee anything if the object you pass it doesn't keep that memory around, but it's a start, and should work at least for the common case of a simple Python string.
I first thought to subclass wx.Image, and make a version that is identical, except that it holds a reference to the buffer object that is used to create it. However, I couldn't' figure out how to do it, because it seems wxImages are all created by different factory functions, so I can't just override the __init__. Can I do this with some kind of judicious calling of wx.Image.__new__?
I've enclosed a simple test of my ImageFromBuffer function. It seems to work. If I don't put the reference to the string in there, I get some garbage. If I do, the image looks fine. would this be a worthwhile small addition to wxPython?
-Chris
ImageBuffer.py (2.39 KB)
···
--
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