Mercurial > hg > orthanc-python
comparison 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 |
comparison
equal
deleted
inserted
replaced
64:091fb1903bfc | 65:4da5ce3468b4 |
---|---|
37 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" | 37 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" |
38 | 38 |
39 #include <boost/algorithm/string/predicate.hpp> | 39 #include <boost/algorithm/string/predicate.hpp> |
40 #include <boost/filesystem.hpp> | 40 #include <boost/filesystem.hpp> |
41 | 41 |
42 | |
43 // The "dl_iterate_phdr()" function (to walk through shared libraries) | 42 // The "dl_iterate_phdr()" function (to walk through shared libraries) |
44 // is not available on Microsoft Windows and Apple OS X | 43 // is not available on Microsoft Windows and Apple OS X |
45 #if defined(_WIN32) | 44 #if defined(_WIN32) |
46 # define HAS_DL_ITERATE 0 | 45 # define HAS_DL_ITERATE 0 |
47 #elif defined(__APPLE__) && defined(__MACH__) | 46 #elif defined(__APPLE__) && defined(__MACH__) |
76 { | 75 { |
77 image = reinterpret_cast<sdk_OrthancPluginImage_Object*>(pixelData)->object_; | 76 image = reinterpret_cast<sdk_OrthancPluginImage_Object*>(pixelData)->object_; |
78 } | 77 } |
79 else | 78 else |
80 { | 79 { |
81 PyErr_SetString(PyExc_TypeError, "Second parameter is not a valid orthanc.Image"); | 80 PyErr_SetString(PyExc_TypeError, "Second parameter is not a valid orthanc.Image object"); |
82 return NULL; | 81 return NULL; |
83 } | 82 } |
84 | 83 |
85 OrthancPlugins::MemoryBuffer buffer; | 84 OrthancPlugins::MemoryBuffer buffer; |
86 OrthancPluginErrorCode code = OrthancPluginCreateDicom(OrthancPlugins::GetGlobalContext(), *buffer, json, image, | 85 OrthancPluginErrorCode code = OrthancPluginCreateDicom(OrthancPlugins::GetGlobalContext(), *buffer, json, image, |
97 } | 96 } |
98 } | 97 } |
99 } | 98 } |
100 | 99 |
101 | 100 |
101 PyObject* GetInstanceData(sdk_OrthancPluginDicomInstance_Object* self, PyObject *args) | |
102 { | |
103 // The GIL is locked at this point (no need to create "PythonLock") | |
104 | |
105 if (self->object_ == NULL) | |
106 { | |
107 PyErr_SetString(PyExc_ValueError, "Invalid object"); | |
108 return NULL; | |
109 } | |
110 else | |
111 { | |
112 OrthancPluginDicomInstance* instance = reinterpret_cast<sdk_OrthancPluginDicomInstance_Object*>(self)->object_; | |
113 | |
114 const void* data = OrthancPluginGetInstanceData(OrthancPlugins::GetGlobalContext(), instance); | |
115 size_t size = OrthancPluginGetInstanceSize(OrthancPlugins::GetGlobalContext(), instance); | |
116 | |
117 if (data == NULL && | |
118 size != 0) | |
119 { | |
120 PyErr_SetString(PyExc_ValueError, "Accessing an invalid orthanc.DicomInstance object"); | |
121 return NULL; | |
122 } | |
123 else | |
124 { | |
125 return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(data), size); | |
126 } | |
127 } | |
128 } | |
129 | |
130 | |
131 /** | |
132 * Contrarily to "OrthancPluginGetImageBuffer()" that provides a | |
133 * read-write pointer, the method "orthanc.Image.GetImageBuffer()" | |
134 * returns a copy of the image buffer. Use "CreateImageFromBuffer()" | |
135 * to create an image from a Python buffer. | |
136 **/ | |
137 PyObject* GetImageBuffer(sdk_OrthancPluginImage_Object* self, PyObject *args) | |
138 { | |
139 // The GIL is locked at this point (no need to create "PythonLock") | |
140 | |
141 if (self->object_ == NULL) | |
142 { | |
143 PyErr_SetString(PyExc_ValueError, "Invalid object"); | |
144 return NULL; | |
145 } | |
146 else | |
147 { | |
148 OrthancPluginImage* image = reinterpret_cast<sdk_OrthancPluginImage_Object*>(self)->object_; | |
149 | |
150 const void* buffer = OrthancPluginGetImageBuffer(OrthancPlugins::GetGlobalContext(), image); | |
151 size_t size = (OrthancPluginGetImagePitch(OrthancPlugins::GetGlobalContext(), image) * | |
152 OrthancPluginGetImageHeight(OrthancPlugins::GetGlobalContext(), image)); | |
153 | |
154 if (buffer == NULL && | |
155 size != 0) | |
156 { | |
157 PyErr_SetString(PyExc_ValueError, "Accessing an invalid orthanc.Image object"); | |
158 return NULL; | |
159 } | |
160 else | |
161 { | |
162 return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer), size); | |
163 } | |
164 } | |
165 } | |
166 | |
167 | |
168 /** | |
169 * This function is the Python alternative for function | |
170 * "OrthancPluginCreateImageAccessor()". Indeed, it is not possible to | |
171 * share a memory buffer between Orthanc and Python, so we have to | |
172 * create a copy of the image. | |
173 **/ | |
174 PyObject* CreateImageFromBuffer(PyObject* module, PyObject* args) | |
175 { | |
176 // The GIL is locked at this point (no need to create "PythonLock") | |
177 | |
178 unsigned long format, width, height, sourcePitch; | |
179 Py_buffer buffer; | |
180 | |
181 if (!PyArg_ParseTuple(args, "kkkks*", &format, &width, &height, &sourcePitch, &buffer)) | |
182 { | |
183 PyErr_SetString(PyExc_TypeError, "5 arguments are needed: image.PixelFormat, width, height, pitch and memory buffer"); | |
184 return NULL; | |
185 } | |
186 else if (static_cast<Py_ssize_t>(sourcePitch * height) != buffer.len) | |
187 { | |
188 PyBuffer_Release(&buffer); | |
189 | |
190 PyErr_SetString(PyExc_TypeError, "The size of the memory buffer must match the product of height by pitch"); | |
191 return NULL; | |
192 } | |
193 else | |
194 { | |
195 OrthancPluginImage* image = OrthancPluginCreateImage( | |
196 OrthancPlugins::GetGlobalContext(), static_cast<OrthancPluginPixelFormat>(format), width, height); | |
197 | |
198 if (image == NULL) | |
199 { | |
200 PyBuffer_Release(&buffer); | |
201 | |
202 PyErr_SetString(PyExc_ValueError, "Cannot create the image"); | |
203 return NULL; | |
204 } | |
205 else | |
206 { | |
207 // Copy the image line by line | |
208 unsigned long targetPitch = OrthancPluginGetImagePitch(OrthancPlugins::GetGlobalContext(), image); | |
209 | |
210 const uint8_t* sourcePixels = reinterpret_cast<const uint8_t*>(buffer.buf); | |
211 uint8_t* targetPixels = reinterpret_cast<uint8_t*>(OrthancPluginGetImageBuffer(OrthancPlugins::GetGlobalContext(), image)); | |
212 | |
213 unsigned long rowSize = std::min(sourcePitch, targetPitch); | |
214 | |
215 for (unsigned int y = 0; y < height; y++) | |
216 { | |
217 memcpy(targetPixels, sourcePixels, rowSize); | |
218 targetPixels += targetPitch; | |
219 sourcePixels += sourcePitch; | |
220 } | |
221 | |
222 PyBuffer_Release(&buffer); | |
223 | |
224 { | |
225 PyObject *argList = Py_BuildValue("Lb", image, false /* not borrowed */); | |
226 PyObject *python = PyObject_CallObject((PyObject *) GetOrthancPluginImageType(), argList); | |
227 Py_DECREF(argList); | |
228 return python; | |
229 } | |
230 } | |
231 } | |
232 } | |
233 | |
234 | |
102 | 235 |
103 static bool pythonEnabled_ = false; | 236 static bool pythonEnabled_ = false; |
104 static std::string userScriptName_; | 237 static std::string userScriptName_; |
105 static std::vector<PyMethodDef> globalFunctions_; | 238 static std::vector<PyMethodDef> globalFunctions_; |
106 | 239 |
155 * New in release 3.2 | 288 * New in release 3.2 |
156 **/ | 289 **/ |
157 | 290 |
158 { | 291 { |
159 PyMethodDef f = { "CreateDicom", CreateDicom, METH_VARARGS, "" }; | 292 PyMethodDef f = { "CreateDicom", CreateDicom, METH_VARARGS, "" }; |
293 functions.push_back(f); | |
294 } | |
295 | |
296 { | |
297 PyMethodDef f = { "CreateImageFromBuffer", CreateImageFromBuffer, METH_VARARGS, "" }; | |
160 functions.push_back(f); | 298 functions.push_back(f); |
161 } | 299 } |
162 | 300 |
163 { | 301 { |
164 PyMethodDef f = { "RegisterFindCallback", RegisterFindCallback, METH_VARARGS, "" }; | 302 PyMethodDef f = { "RegisterFindCallback", RegisterFindCallback, METH_VARARGS, "" }; |