I’ve got a library that takes in a very simple C image structure:
// Represents a one-channel 8-bit image
typedef struct simple_image_t {
uint32 rows;
uint32 cols;
uint8 *imgdata;
} simple_image;
I didn’t create this library, nor this structure, so I can’t change it. I’m responsible for wrapping this library for python using SWIG. The Python wrapper needs to be able to take in a PIL Image and convert it into this structure. Here’s how I’m doing it right now (using a SWIG %inline%):
// Allows python to easily create and initialize this structure
simple_image* py_make_simple_image(uint32 width, uint32 height)
{
simple_image* img = new simple_image();
img->rows = height;
img->cols = width;
img->imgdata = new uint8[height * width];
return img;
}
// Allows python to set a particular pixel value
void py_set_simple_image(simple_image* img, uint32 pos, uint8 val)
{
img->imgdata[pos] = val;
}
And then on the python wrapper side here’s how things look right now:
# Make sure it's an 8-bit image
if pil_image.mode != "L":
pil_image = pil_image.convert("L")
# Create the simple image structure
(width, height) = pil_image.size
img = swig_wrapper.py_make_simple_image(width, height)
try:
# Copy the image data into the simple image structure
pos = 0
for pixel in pil_image.getdata():
swig_wrapper.py_set_simple_image(img, pos, pixel)
pos += 1
# Call some library method that accepts a simple_image*
return swig_wrapper.some_image_method(img)
finally:
# Clean up the simple image structure
swig_wrapper.py_destroy_simple_image(img)
Amazingly this works, however as you may have guessed it’s incredibly slow when working with even moderately large images. I know with SWIG the proper way to do things is to use a typemap, however that would mean digging in to the C API of PIL, and I just didn’t have time to do that at the moment.
What are my options in terms of speed? Are there quicker ways of marshaling the pixel data from a PIL image to this simple image structure? Has someone already done this and my Google skills are just that bad? Am I just boned and soon will need to learn the internals of PIL?
Thanks.
PIL’s
Image.tostring()returns a string of the exact data you need forimgdata. The typemap I used is fairly simple, but not perfect, which I’ll note below. Here is the sample code I created on Windows that worked for me:sample.h
sample.c
sample.i
makefile
example.py
With this quick example I haven’t determined how the typemap should correctly increment the reference count of the string object. Note that the above code could crash if the following code were used:
The current typemap’s
PyString_AsStringAndSizereturns a direct pointer to the PyString object’s buffer, but doesn’t increment the reference count for the object. It can be garbage collected beforesome_funcexecutes (and was for me, crashing Python). Assigning toskeeps a reference to the string and prevents problems. The typemap should copy the buffer, but you were looking for speed so this hack may be what you want.