]> Creatis software - gdcm.git/blob - gdcmPython/gdcm.i
ENH: Finally found a version of GetMacAddress that actually works on Sun/Solaris...
[gdcm.git] / gdcmPython / gdcm.i
1 %module gdcm
2 %{
3 #include "gdcmCommon.h"
4 #include "gdcmBase.h"
5 #include "gdcmDict.h"
6 #include "gdcmDictEntry.h"
7 #include "gdcmDictSet.h"
8 #include "gdcmDicomDir.h"
9 #include "gdcmDicomDirElement.h"
10 #include "gdcmDicomDirImage.h"
11 #include "gdcmDicomDirMeta.h"
12 #include "gdcmDicomDirObject.h"
13 #include "gdcmDicomDirPatient.h"
14 #include "gdcmDicomDirStudy.h"
15 #include "gdcmDicomDirSerie.h"
16 #include "gdcmDocEntrySet.h"
17 #include "gdcmDocument.h"
18 #include "gdcmElementSet.h"
19 #include "gdcmFile.h"
20 #include "gdcmGlobal.h"
21 #include "gdcmHeader.h"
22 #include "gdcmSerieHeader.h"
23 #include "gdcmRLEFramesInfo.h"
24 #include "gdcmJPEGFragmentsInfo.h"
25 #include "gdcmSQItem.h"
26 #include "gdcmUtil.h"
27 #include "gdcmDocEntry.h"
28 #include "gdcmValEntry.h"
29 #include "gdcmBinEntry.h"
30 #include "gdcmSeqEntry.h"
31
32 ////////////////////////////////////////////////////////////////////////////
33 /// Refer (below) to the definition of multi-argument typemap
34 ///   %typemap(python, in)
35 ///      ( gdcm::DicomDir::Method*, void*, gdcm::DicomDir::Method*)
36 /// for detail on gdcmPythonVoidFunc() and gdcmPythonVoidFuncArgDelete().
37 void gdcmPythonVoidFunc(void *arg)
38 {
39    PyObject *arglist, *result;
40    PyObject *func = (PyObject *)arg;
41
42    arglist = Py_BuildValue("()");
43
44    result = PyEval_CallObject(func, arglist);
45    Py_DECREF(arglist);
46
47    if (result)
48    {
49       Py_XDECREF(result);
50    }
51    else
52    {
53       if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
54       {
55          std::cerr << "Caught a Ctrl-C within python, exiting program.\n";
56          Py_Exit(1);
57       }
58       PyErr_Print();
59    }
60 }
61
62 void gdcmPythonVoidFuncArgDelete(void *arg)
63 {
64    PyObject *func = (PyObject *)arg;
65    if (func)
66    {
67       Py_DECREF(func);
68    }
69 }
70
71 /// This is required in order to avoid %including all the gdcm include files.
72 using namespace gdcm;
73 %}
74
75
76 ///////////////////////  typemap section  ////////////////////////////////////
77
78 ////////////////////////////////////////////////
79 // Convert a DocEntry * to the real derived class
80 %typemap(out) gdcm::DocEntry * 
81 {
82    PyObject *newEntry;
83
84    if($1)
85    {
86       if(dynamic_cast<SeqEntry *>($1)) // SeqEntry *
87          newEntry = SWIG_NewPointerObj($1,SWIGTYPE_p_gdcm__SeqEntry,0);
88       else if(dynamic_cast<BinEntry *>($1)) // BinEntry *
89          newEntry = SWIG_NewPointerObj($1,SWIGTYPE_p_gdcm__BinEntry,0);
90       else // ValEntry *
91          newEntry = SWIG_NewPointerObj($1,SWIGTYPE_p_gdcm__ValEntry,0);
92    }
93    else
94    {
95       newEntry = Py_BuildValue("");
96    }
97    $result = newEntry;
98 }
99
100 ////////////////////////////////////////////////
101 // Convert an STL list<> to a python native list
102 %typemap(out) std::list<std::string> * 
103 {
104    PyObject *newItem = (PyObject *)0;
105    PyObject *newList = PyList_New(0); // The result of this typemap
106
107    for (std::list<std::string>::iterator strIt = ($1)->begin();
108         strIt != ($1)->end();
109         ++strIt)
110    {
111       newItem = PyString_FromString(strIt->c_str());
112       PyList_Append( newList, newItem);
113    }
114    $result = newList;
115 }
116
117 //////////////////////////////////////////////////////////////////
118 // Convert an STL map<> (hash table) to a python native dictionary
119 %typemap(out) std::map<std::string, std::list<std::string> > * 
120 {
121    PyObject *newDict = PyDict_New(); // The result of this typemap
122    PyObject *newKey = (PyObject *)0;
123    PyObject *newVal = (PyObject *)0;
124
125    for (std::map<std::string,
126         std::list<std::string> >::iterator tag = ($1)->begin();
127         tag != ($1)->end(); ++tag)
128    {
129       std::string first = tag->first;
130       // Do not publish entries whose keys is made of spaces
131       if (first.length() == 0)
132          continue;
133       newKey = PyString_FromString(first.c_str());
134
135       PyObject *newList = PyList_New(0);
136       for (std::list<std::string>::iterator itemIt = tag->second.begin();
137            itemIt != tag->second.end();
138            ++itemIt)
139       {
140          newVal = PyString_FromString(itemIt->c_str());
141          PyList_Append( newList, newVal);
142       }
143       PyDict_SetItem( newDict, newKey, newList);
144    }
145    $result = newDict;
146 }
147
148 /////////////////////////////////////////////////////////
149 // Convert a c++ hash table in a python native dictionary
150 %typemap(out) gdcm::TagDocEntryHT & 
151 {
152    PyObject *newDict = PyDict_New(); // The result of this typemap
153    std::string rawName;              // Element name as gotten from gdcm
154    PyObject *newKey = (PyObject *)0; // Associated name as python object
155    std::string rawValue;             // Element value as gotten from gdcm
156    PyObject *newVal = (PyObject *)0; // Associated value as python object
157
158    for (gdcm::TagDocEntryHT::iterator tag = $1->begin(); tag != $1->end(); ++tag)
159    {
160       // The element name shall be the key:
161       rawName = tag->second->GetName();
162       // gdcm unrecognized (including not loaded because their size exceeds
163       // the user specified treshold) elements are exported with their
164       // TagKey as key.
165       if (rawName == "Unknown")
166          rawName = tag->second->GetKey();
167       newKey = PyString_FromString(rawName.c_str());
168
169       // Element values are striped from leading/trailing spaces
170       gdcm::ValEntry *valEntryPtr = dynamic_cast< gdcm::ValEntry* >(tag->second);
171       if ( valEntryPtr )
172       {
173          rawValue = valEntryPtr->GetValue();
174       }
175       else
176         continue; 
177       newVal = PyString_FromString(rawValue.c_str());
178       PyDict_SetItem( newDict, newKey, newVal);
179    }
180    $result = newDict;
181 }
182
183 /////////////////////////////////////
184 %typemap(out) ListDicomDirPatient & 
185 {
186         PyObject *newItem = (PyObject *)0;
187         $result = PyList_New(0); // The result of this typemap
188
189         for (std::list<gdcm::DicomDirPatient *>::iterator newIt = ($1)->begin();
190             newIt != ($1)->end(); ++newIt)
191    {
192                 newItem = SWIG_NewPointerObj(*newIt,SWIGTYPE_p_DicomDirPatient,0);
193                 PyList_Append($result, newItem);
194         }
195 }
196
197 %typemap(out) ListDicomDirStudy & 
198 {
199         PyObject *newItem = (PyObject *)0;
200         $result = PyList_New(0); // The result of this typemap
201
202         for (std::list<gdcm::DicomDirStudy *>::iterator newIt = ($1)->begin();
203             newIt != ($1)->end(); ++newIt)
204    {
205                 newItem = SWIG_NewPointerObj(*newIt,SWIGTYPE_p_DicomDirStudy,0);
206                 PyList_Append($result, newItem);
207         }
208 }
209
210 %typemap(out) ListDicomDirSerie & 
211 {
212         PyObject* newItem = (PyObject*)0;
213         $result = PyList_New(0); // The result of this typemap
214
215         for (std::list<gdcm::DicomDirSerie *>::iterator newIt = ($1)->begin();
216             newIt != ($1)->end(); ++newIt)
217    {
218                 newItem = SWIG_NewPointerObj(*newIt,SWIGTYPE_p_DicomDirSerie,0);
219                 PyList_Append($result, newItem);
220         }
221 }
222
223 %typemap(out) ListDicomDirImage & 
224 {
225         PyObject* newItem = (PyObject*)0;
226         $result = PyList_New(0); // The result of this typemap
227
228         for (std::list<gdcm::DicomDirImage *>::iterator newIt = ($1)->begin();
229             newIt != ($1)->end(); ++newIt) 
230    {
231                 newItem = SWIG_NewPointerObj(*newIt,SWIGTYPE_p_DicomDirImage,0);
232                 PyList_Append($result, newItem);
233         }
234 }
235
236 ////////////////////////////////////////////////////////////////////////////
237 // Multi-argument typemap designed for wrapping the progress related methods
238 // in order to control from an external application the computation of
239 // a DicomDir object (see DicomDir::SetStartMethod*,
240 // DicomDir::SetProgressMethod* and DicomDir::SetEndMethod*).
241 // Motivation: since DicomDir parsing can be quite long, a GUI application
242 //             needs to display the avancement and potentially offer a
243 //             cancel method to the user (when this one feels things are
244 //             longer than expected).
245 // Example of usage: refer to demo/DicomDirProgressMethod.py
246 // Note: Uses gdcmPythonVoidFunc and gdcmPythonVoidFuncArgDelete defined
247 //       in the Swig verbatim section of this gdcm.i i.e. in the above section
248 //       enclosed within the %{ ... %} scope operator ).
249 %typemap(python, in) ( gdcm::DicomDir::Method *, 
250                        void * = NULL, 
251                        gdcm::DicomDir::Method * = NULL )
252 {
253         if($input!=Py_None)
254         {
255                 Py_INCREF($input);
256                 $1=gdcmPythonVoidFunc;
257                 $2=$input;
258                 $3=gdcmPythonVoidFuncArgDelete;
259         }
260         else
261         {
262                 $1=NULL;
263                 $2=NULL;
264                 $3=NULL;
265         }
266 }
267
268 ////////////////////  STL string versus Python str  ////////////////////////
269 // Convertion returning a C++ string.
270 %typemap(out) string, std::string 
271 {
272     $result = PyString_FromString(($1).c_str());
273 }
274
275 // Convertion of incoming Python str to STL string
276 %typemap(python, in) const std::string, std::string
277 {
278   $1 = PyString_AsString($input);
279 }
280
281 // Same convertion as above but references (since swig converts C++
282 // refererences to pointers)
283 %typemap(python, in) std::string const &
284 {
285    $1 = new std::string( PyString_AsString( $input ) );
286 }
287
288 ////////////////////////////////////////////////////////////////////////////
289 // Because overloading and %rename don't work together (see below Note 1)
290 // we need to ignore some methods (e.g. the overloaded default constructor).
291 // The gdcm::Header class doesn't have any SetFilename method anyhow, and
292 // this constructor is only used internaly (not from the API) so this is
293 // not a big loss.
294 %ignore gdcm::binary_write(std::ostream &,uint32_t const &);
295 %ignore gdcm::binary_write(std::ostream &,uint16_t const &);
296
297 %ignore gdcm::Header::Header();
298 %ignore gdcm::DicomDir::DicomDir();
299
300 // Ignore all placed in gdcmCommon.h
301 %ignore GDCM_UNKNOWN;
302 %ignore GDCM_UNFOUND;
303 %ignore GDCM_BINLOADED;
304 %ignore GDCM_NOTLOADED;
305 %ignore GDCM_UNREAD;
306
307 ////////////////////////////////////////////////////////////////////////////
308 // Warning: Order matters !
309 %include "gdcmCommon.h"
310 %include "gdcmBase.h"
311 %include "gdcmDictEntry.h"
312 %include "gdcmDict.h"
313 %include "gdcmDocEntrySet.h"
314 %include "gdcmElementSet.h"
315 %include "gdcmDictSet.h"
316 %include "gdcmSQItem.h"
317 %include "gdcmDicomDirElement.h"
318 %include "gdcmDicomDirObject.h"
319 %include "gdcmDicomDirImage.h"
320 %include "gdcmDicomDirSerie.h"
321 %include "gdcmDicomDirStudy.h"
322 %include "gdcmDicomDirPatient.h"
323 %include "gdcmDicomDirMeta.h"
324 %include "gdcmDocument.h"
325 %include "gdcmHeader.h"
326 %include "gdcmSerieHeader.h"
327 %include "gdcmFile.h"
328 %include "gdcmUtil.h"
329 %include "gdcmGlobal.h"
330 %include "gdcmDicomDir.h"
331 %include "gdcmDocEntry.h"
332 %include "gdcmValEntry.h"
333 %include "gdcmBinEntry.h"
334 %include "gdcmSeqEntry.h"
335
336 ////////////////////////////////////////////////////////////////////////////
337 // Notes on swig and this file gdcm.i:
338 //
339 /////////////////////////////////////
340 // Note 1: swig collision of method overloading and %typemap
341 // Consider the following junk.i file:
342 //     %module junk
343 //     %{
344 //     #include <string>
345 //     #include <iostream>
346 //     void Junk(std::string const & bozo) { std::cout << bozo << std::endl; }
347 //     void Junk() { std::cout << "Renamed Junk()" << std::endl; }
348 //     %}
349 //   
350 //     %typemap(python, in) std::string const &
351 //     {
352 //     $1 = new std::string( PyString_AsString( $input ) );
353 //     }
354 //     void Junk();
355 //     void Junk(std::string const & bozo);
356 //
357 // that we compile on linux with:
358 //    swig -c++ -python junk.i
359 //    g++ -g -I/usr/include/python2.3/ -o junk_wrap.o -c junk_wrap.cxx
360 //    g++ junk_wrap.o -shared -g -o _junk.so -L/usr/lib/python2.3/config \
361 //        -lpython2.3
362 // and invoque with:
363 //    python -c 'from junk import *; Junk("aaa") '
364 // then we get the following unexpected (for novice) python TypeError:
365 //    TypeError: No matching function for overloaded 'Junk'
366 //
367 // This happens because the swig generated code (at least for python) does
368 // the following two stage process:
369 //   1/ first do a dynamic dispatch ON THE NUMBER OF ARGUMENTS of the overloaded
370 //      Junk function (the same happens with method of course). [Note that the
371 //      dispatch is NOT done on the type of the arguments].
372 //   2/ second apply the typemap.
373 // When the first dynamic dispatch is executed, the swig generated code
374 // has no knowledge of the typemap, and thus expects a pointer to a std::string
375 // type i.e. an argument to Junk of the form _p_std__int<address>. But this
376 // is not what python handles to Junk ! An invocation of the form 'Junk("aaa")'
377 // will make Python pass a PyString to swig (and this is precisely why we
378 // wrote the typemap). And this will fail....
379 /////////////////////////////////////