How to pass Numpy PyArray* via FFI
<p>Idea is to be able to modify array from library, like an "output" from a function.
Example:</p>

<pre><code>ffi.cdef("""
    //Reads data from a file, and store in the numpy array
    void read_image(PyArray* arr);
""")

C = ffi.dlopen('libimage.so')
image = np.array([], dtype=np.float32)
C.read_image(image)
assert image.ndim == 2
</code></pre>

<p>You can't pass CPython-specific <code>PyXxx</code> structures via CFFI: you need to pass standard C data.  Normally I'd answer that you need to design your cdef()'ed function with a standard C interface, for example something like:</p>

<pre><code>ffi.cdef("""
    struct myimage_t {
        int width, height;
        float *data;
    };
    int read_image(struct myimage_t *output);  // fill in '*output'
    void free_image(struct myimage_t *img);   // free output-&gt;data
""")

myimage = ffi.new("struct myimage_t *")
if lib.read_image(myimage) &lt; 0:
    raise IOError
...
lib.free_image(myimage)
</code></pre>

<p>Then you need to manually convert the <code>myimage</code> to a numpy array, somewhere in the "..." code above.</p>

<p>One better alternative is to use a Python callback: a callback that makes the numpy array according to spec and returns a C-standard <code>float *</code> pointer.  The numpy array itself is saved somewhere in the callback.  You could save it as a Python global, or more cleanly use a "handle" you pass via C.  Requires the API version, not the ABI.  In _example_build.py:</p>

<pre><code>ffi.cdef("""
   extern "Python" float *alloc_2d_numpy_array(void *handle, int w, int h);
   void read_image(void *handle);
""")
ffi.set_source("_example_cffi", """
   void read_image(void *handle)
   {
       // the C code that eventually invokes
       float *p = alloc_2d_numpy_array(handle, w, h);
        // and then fill the data at 'p'
   }
""")
ffi.compile(verbose=True)
</code></pre>

<p>In file example.py:</p>

<pre><code>from _example_cffi import ffi, lib

class Context:
    pass

@ffi.def_extern()
def alloc_2d_numpy_array(handle, w, h):
    context = ffi.from_handle(handle)
    context.image = np.ndarray([w, h], dtype=np.float32)
    return ffi.cast("float *", ffi.from_buffer(context.image))

context = Context()
lib.read_image(ffi.new_handle(context))
image = context.image
</code></pre>

python numpy python-cffi