Mercurial > hg > orthanc-python
diff Sources/Plugin.cpp @ 65:4da5ce3468b4
new wrapped functions: CreateImageFromBuffer(), DicomInstance.GetInstanceData() and Image.GetImageBuffer()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 11 Jun 2021 12:47:18 +0200 |
parents | 091fb1903bfc |
children | 6fc445793796 |
line wrap: on
line diff
--- a/Sources/Plugin.cpp Fri Jun 11 09:03:43 2021 +0200 +++ b/Sources/Plugin.cpp Fri Jun 11 12:47:18 2021 +0200 @@ -39,7 +39,6 @@ #include <boost/algorithm/string/predicate.hpp> #include <boost/filesystem.hpp> - // The "dl_iterate_phdr()" function (to walk through shared libraries) // is not available on Microsoft Windows and Apple OS X #if defined(_WIN32) @@ -78,7 +77,7 @@ } else { - PyErr_SetString(PyExc_TypeError, "Second parameter is not a valid orthanc.Image"); + PyErr_SetString(PyExc_TypeError, "Second parameter is not a valid orthanc.Image object"); return NULL; } @@ -99,6 +98,140 @@ } +PyObject* GetInstanceData(sdk_OrthancPluginDicomInstance_Object* self, PyObject *args) +{ + // The GIL is locked at this point (no need to create "PythonLock") + + if (self->object_ == NULL) + { + PyErr_SetString(PyExc_ValueError, "Invalid object"); + return NULL; + } + else + { + OrthancPluginDicomInstance* instance = reinterpret_cast<sdk_OrthancPluginDicomInstance_Object*>(self)->object_; + + const void* data = OrthancPluginGetInstanceData(OrthancPlugins::GetGlobalContext(), instance); + size_t size = OrthancPluginGetInstanceSize(OrthancPlugins::GetGlobalContext(), instance); + + if (data == NULL && + size != 0) + { + PyErr_SetString(PyExc_ValueError, "Accessing an invalid orthanc.DicomInstance object"); + return NULL; + } + else + { + return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(data), size); + } + } +} + + +/** + * Contrarily to "OrthancPluginGetImageBuffer()" that provides a + * read-write pointer, the method "orthanc.Image.GetImageBuffer()" + * returns a copy of the image buffer. Use "CreateImageFromBuffer()" + * to create an image from a Python buffer. + **/ +PyObject* GetImageBuffer(sdk_OrthancPluginImage_Object* self, PyObject *args) +{ + // The GIL is locked at this point (no need to create "PythonLock") + + if (self->object_ == NULL) + { + PyErr_SetString(PyExc_ValueError, "Invalid object"); + return NULL; + } + else + { + OrthancPluginImage* image = reinterpret_cast<sdk_OrthancPluginImage_Object*>(self)->object_; + + const void* buffer = OrthancPluginGetImageBuffer(OrthancPlugins::GetGlobalContext(), image); + size_t size = (OrthancPluginGetImagePitch(OrthancPlugins::GetGlobalContext(), image) * + OrthancPluginGetImageHeight(OrthancPlugins::GetGlobalContext(), image)); + + if (buffer == NULL && + size != 0) + { + PyErr_SetString(PyExc_ValueError, "Accessing an invalid orthanc.Image object"); + return NULL; + } + else + { + return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer), size); + } + } +} + + +/** + * This function is the Python alternative for function + * "OrthancPluginCreateImageAccessor()". Indeed, it is not possible to + * share a memory buffer between Orthanc and Python, so we have to + * create a copy of the image. + **/ +PyObject* CreateImageFromBuffer(PyObject* module, PyObject* args) +{ + // The GIL is locked at this point (no need to create "PythonLock") + + unsigned long format, width, height, sourcePitch; + Py_buffer buffer; + + if (!PyArg_ParseTuple(args, "kkkks*", &format, &width, &height, &sourcePitch, &buffer)) + { + PyErr_SetString(PyExc_TypeError, "5 arguments are needed: image.PixelFormat, width, height, pitch and memory buffer"); + return NULL; + } + else if (static_cast<Py_ssize_t>(sourcePitch * height) != buffer.len) + { + PyBuffer_Release(&buffer); + + PyErr_SetString(PyExc_TypeError, "The size of the memory buffer must match the product of height by pitch"); + return NULL; + } + else + { + OrthancPluginImage* image = OrthancPluginCreateImage( + OrthancPlugins::GetGlobalContext(), static_cast<OrthancPluginPixelFormat>(format), width, height); + + if (image == NULL) + { + PyBuffer_Release(&buffer); + + PyErr_SetString(PyExc_ValueError, "Cannot create the image"); + return NULL; + } + else + { + // Copy the image line by line + unsigned long targetPitch = OrthancPluginGetImagePitch(OrthancPlugins::GetGlobalContext(), image); + + const uint8_t* sourcePixels = reinterpret_cast<const uint8_t*>(buffer.buf); + uint8_t* targetPixels = reinterpret_cast<uint8_t*>(OrthancPluginGetImageBuffer(OrthancPlugins::GetGlobalContext(), image)); + + unsigned long rowSize = std::min(sourcePitch, targetPitch); + + for (unsigned int y = 0; y < height; y++) + { + memcpy(targetPixels, sourcePixels, rowSize); + targetPixels += targetPitch; + sourcePixels += sourcePitch; + } + + PyBuffer_Release(&buffer); + + { + PyObject *argList = Py_BuildValue("Lb", image, false /* not borrowed */); + PyObject *python = PyObject_CallObject((PyObject *) GetOrthancPluginImageType(), argList); + Py_DECREF(argList); + return python; + } + } + } +} + + static bool pythonEnabled_ = false; static std::string userScriptName_; @@ -161,6 +294,11 @@ } { + PyMethodDef f = { "CreateImageFromBuffer", CreateImageFromBuffer, METH_VARARGS, "" }; + functions.push_back(f); + } + + { PyMethodDef f = { "RegisterFindCallback", RegisterFindCallback, METH_VARARGS, "" }; functions.push_back(f); }