1

I'm using the SWIG array_class macro defined in carrays.i to create an unsigned char buffer which can be sent to the c++-side of my project, which handles picture taking. This works fine – the buffer is filled width data after the camera has triggered, and I can dereference the buffer using [] from python to see what it holds. I now want to create a PIL image from that buffer, using Image.frombuffer:

Image.frombuffer(mode, size, data) => image

(New in PIL 1.1.4). Creates an image memory from pixel data in a string or buffer object, using the standard "raw" decoder.

but I get an error message telling me that the SWIG object I supply is not a python buffer:

File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 1853, in frombuffer
core.map_buffer(data, size, decoder_name, None, 0, args)
TypeError: expected string or buffer

How can I make this proxy of a SWIG Object compatible with the type of buffer that Image.frombuffer expects?

Misa Lazovic
  • 2,805
  • 10
  • 32
  • 38
Paul
  • 257
  • 1
  • 3
  • 10
  • 1
    I'm not sure if it should work with a buffer (probably it should). I just wanted to note that I like to bridge all image data via NumPy arrays. IMO it's easier to manipulate NumPy Python objects directly from C++ than trying to make SWIG generate the right code. I have some [sample code](https://github.com/martinxyz/python/blob/master/realistic/hello.hpp) online. You could let SWIG wrap a method that returns a PyObject*, and return a new NumPy object created with PyArray_SimpleNew(). – maxy Jan 11 '12 at 20:29
  • 1
    Do you know the length of the carray type somewhere? – Flexo Jan 13 '12 at 00:15

1 Answers1

0

If you can deal with coercing the signedness of your SWIG buffer, you can create a PIL ImagingMemoryInstance directly. In libImaging/Imaging.h you will find this:

struct ImagingMemoryInstance {

    /* Format */
    char mode[4+1]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK") */
    int type;       /* Data type (IMAGING_TYPE_*) */
    int depth;      /* Depth (ignored in this version) */
    int bands;      /* Number of bands (1, 2, 3, or 4) */
    int xsize;      /* Image dimension. */
    int ysize;

    /* Colour palette (for "P" images only) */
    ImagingPalette palette;

    /* Data pointers */
    UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */
    INT32 **image32;    /* Set for 32-bit images (pixelsize=4). */

    /* Internals */
    char **image;   /* Actual raster data. */
    char *block;    /* Set if data is allocated in a single block. */

    int pixelsize;  /* Size of a pixel, in bytes (1, 2 or 4) */
    int linesize;   /* Size of a line, in bytes (xsize * pixelsize) */

    /* Virtual methods */
    void (*destroy)(Imaging im);
};

... ImagingMemoryInstance* is typedef'd to Imaging, which is the base struct you'll find ubiquitously throughout the PIL C extension source. Don't take my word for it, have a look -- as far as API source goes, the PIL codebase is notably legible and pretty coherent.

As @maxy points out, you can also create a NumPy array struct just as easy (if not easier) -- but while the NumPy C API is as stable as out of Guido's personal playbook, I personally find that one library-source dependency is enough, in these scenarios.

fish2000
  • 4,289
  • 2
  • 37
  • 76
  • Also: this isn't a SWIG proxy, but: check out the buffer this guy sets up to go back and forth with PIL: https://bitbucket.org/ynil/pyccv/src/d201d144e8e9/src/pyccv/__init__.py ... the RGBImage python class is actually a C struct whose byte layout is analogous to a NumPy array equivalent dtype. I don't know ctypes like a boss, but if I had your problem I'd play with something like that. – fish2000 Mar 15 '12 at 14:04