Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 109 additions & 44 deletions src/pymmcore/pymmcore_swig.i
Original file line number Diff line number Diff line change
Expand Up @@ -55,33 +55,44 @@ import_array();

%typemap(out) void*
{
npy_intp dims[2];
dims[0] = (arg1)->getImageHeight();
dims[1] = (arg1)->getImageWidth();
npy_intp pixelCount = dims[0] * dims[1];
// nullptr, return None
if (result == NULL) {
Py_INCREF(Py_None);
$result = Py_None;
return $result;
}

int width, height, bytesPerPixel, numComponents;
(arg1)->getImageProperties(result, width, height, bytesPerPixel, numComponents);
int pixelCount = width * height;
npy_intp dims[2] = {height, width};

if ((arg1)->getBytesPerPixel() == 1)
if (bytesPerPixel == 1)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT8);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount);
(arg1)->releaseReadAccess(result);
$result = numpyArray;
}
else if ((arg1)->getBytesPerPixel() == 2)
else if (bytesPerPixel == 2)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT16);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount * 2);
(arg1)->releaseReadAccess(result);
$result = numpyArray;
}
else if ((arg1)->getBytesPerPixel() == 4)
else if (bytesPerPixel == 4)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT32);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount * 4);
(arg1)->releaseReadAccess(result);
$result = numpyArray;
}
else if ((arg1)->getBytesPerPixel() == 8)
else if (bytesPerPixel == 8)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT64);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount * 8);
(arg1)->releaseReadAccess(result);
$result = numpyArray;
}
else
Expand All @@ -94,53 +105,94 @@ import_array();
}
}

// This is conceptually similar to the void* typemap above,
// but requires slightly different calls because BufferDataPointer
// is different from the data-returning void* methods of the Core.
%typemap(out) BufferDataPointerVoidStar {

npy_intp numBytes = (arg1)->getSizeBytes();
// nullptr, return None
if (numBytes == 0) {
Py_INCREF(Py_None);
$result = Py_None;
return $result;
}

%typemap(out) unsigned int*
{
//Here we assume we are getting RGBA (32 bits).
npy_intp dims[3];
dims[0] = (arg1)->getImageHeight();
dims[1] = (arg1)->getImageWidth();
dims[2] = 3; // RGB
unsigned numChannels = (arg1)->getNumberOfComponents();
unsigned char * pyBuf;
unsigned char * coreBuf = (unsigned char *) result;

if ((arg1)->getBytesPerPixel() == 4 && numChannels == 1)
{

// create new numpy array object
PyObject * numpyArray = PyArray_SimpleNew(3, dims, NPY_UINT8);

// get a pointer to the data buffer
pyBuf = (unsigned char *) PyArray_DATA((PyArrayObject *) numpyArray);

// copy R,G,B but leave out A in RGBA to return a WxHx3-dimensional array

long pixelCount = dims[0] * dims[1];

for (long i=0; i<pixelCount; ++i)
{
*pyBuf++ = *coreBuf++; //R
*pyBuf++ = *coreBuf++; //G
*pyBuf++ = *coreBuf++; //B

++coreBuf; // Skip the empty byte
}

// Return the numpy array object

int width, height, bytesPerPixel, numComponents;
bool propertiesOK = (arg1)->getImageProperties(width, height, bytesPerPixel, numComponents);

// If getImageProperties fails, its not image data. Assume 1 byte per pixel
// If more data types are supported in the future, could add other
// checks here to return other data types.
if (!propertiesOK) {
bytesPerPixel = 1;
numComponents = 1;
int pixelCount = numBytes;
npy_intp dims[1] = {pixelCount};

PyObject * numpyArray = PyArray_SimpleNew(1, dims, NPY_UINT8);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount);
$result = numpyArray;
return $result;
}

int pixelCount = width * height;
npy_intp dims[2] = {height, width};

if (bytesPerPixel == 1)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT8);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount);
// No realease here because that is done explicitly for BufferDataPointer
$result = numpyArray;
}
else if (bytesPerPixel == 2)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT16);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount * 2);
// No realease here because that is done explicitly for BufferDataPointer
$result = numpyArray;
}
else if (bytesPerPixel == 4)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT32);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount * 4);
// No realease here because that is done explicitly for BufferDataPointer
$result = numpyArray;
}
else if (bytesPerPixel == 8)
{
PyObject * numpyArray = PyArray_SimpleNew(2, dims, NPY_UINT64);
memcpy(PyArray_DATA((PyArrayObject *) numpyArray), result, pixelCount * 8);
// No realease here because that is done explicitly for BufferDataPointer
$result = numpyArray;
}
else
{
// don't know how to map
// TODO: thow exception?
// XXX Must do something, as returning NULL without setting error results
// in an opaque error.
$result = 0;
}
}
}


// Unlike void* above, this alias to void* is mapped to long so it can be used as a pointer
// address instead of having the data it points to copied
%typemap(out) DataPtr {
// Convert the DataPtr to a Python integer
$result = PyLong_FromVoidPtr((void *)$1);
}

%typemap(in) DataPtr {
// Convert the Python integer back to a DataPtr
$1 = (DataPtr)PyLong_AsVoidPtr($input);
}




/* tell SWIG to treat char ** as a list of strings */
/* From https://stackoverflow.com/questions/3494598/passing-a-list-of-strings-to-from-python-ctypes-to-c-function-expecting-char */
/* XXX No need to freearg the vector, right? */
Expand Down Expand Up @@ -288,6 +340,7 @@ import_array();
#include "ImageMetadata.h"
#include "MMEventCallback.h"
#include "MMCore.h"
#include "NewDataBufferPointer.h"
%}

// Exception handling. Tranditionally, MMCore uses exception specifications
Expand Down Expand Up @@ -395,9 +448,21 @@ namespace std {
%apply int &OUTPUT { int &xSize };
%apply int &OUTPUT { int &ySize };

%apply int &OUTPUT { int &width };
%apply int &OUTPUT { int &height };
%apply int &OUTPUT { int &byteDepth };
%apply int &OUTPUT { int &nComponents };

// These are needed by the void* typemaps to copy pixels and then
// release them, but they shouldn't be needed by pymmcore
// because their functionality is handled by the BufferDataPointer class
%ignore CMMCore::getImageProperties(DataPtr, int&, int&, int&, int&);
%ignore CMMCore::releaseReadAccess(DataPtr);

%include "MMDeviceConstants.h"
%include "Error.h"
%include "Configuration.h"
%include "MMCore.h"
%include "ImageMetadata.h"
%include "MMEventCallback.h"
%include "NewDataBufferPointer.h"
Loading