diff --git a/Wrapping/Common/mitk_swig_macros.i b/Wrapping/Common/mitk_swig_macros.i index 9ab07200c4..5f7c949163 100644 --- a/Wrapping/Common/mitk_swig_macros.i +++ b/Wrapping/Common/mitk_swig_macros.i @@ -1,196 +1,196 @@ // // This file contains macros for swig. // // // SWIG_ADD_MITK_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_MITK_CLASS(classname, classinclude, nspace) // Include the include file in the generated cpp file %{ - #include < classinclude > + #include < ## classinclude ## > typedef nspace ## :: ## classname classname ## ; using nspace ## :: ## classname ; %} // Include the given header, where the class definition is found - %include + %include < ## classinclude ## > using nspace ##:: ## classname ; // Declaring that this class is a smart-pointer class, in order to handle // online upcasting where necessary (for example python) %feature("smartptr", noblock=1) nspace ##:: ## classname { itk::SmartPointer } // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname ## ::Pointer >; %template(Vector ## classname) std::vector< nspace ## :: ## classname ## ::Self *>; // Defining the Smartpointer, allows easy access in target language %template(classname ## Pointer) itk::SmartPointer; // Define a conversion method to convert from and to types %template(ConvertTo ## classname) ConvertTo< nspace ##:: ## classname ## >; // This extend is necessary to have the automatic cast methods available %extend itk::SmartPointer< nspace ## :: ## classname ## ::Self> { %pythoncode %{ def _GetListOfValidItems(self): return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %extend std::vector< nspace ## :: ## classname *>::value_type { %pythoncode %{ def _GetListOfValidItems(self): return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %pythoncode %{ convertion_list['classname'] = ConvertTo ## classname %} %enddef // // SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_NONOBJECT_CLASS(classname, classinclude, nspace) // Include the include file in the generated cpp file %{ - #include < classinclude > + #include < ## classinclude ## > typedef nspace ## :: ## classname classname ## ; using nspace ## :: ## classname ; %} // Include the given header, where the class definition is found - %include + %include < ## classinclude ## > using nspace ##:: ## classname ; // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; class nspace ## :: ## classname ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; %template(Vector ## classname) std::vector< nspace ## :: ## classname >; %enddef // // SWIG_ADD_NONOBJECT_TEMPLATECLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_NONOBJECT_TEMPLATECLASS(classname, classinclude, nspace, tmplstring) // Include the include file in the generated cpp file %{ - #include < classinclude > + #include < ## classinclude ## > typedef nspace ## :: ## classname classname ## ; using nspace ## :: ## classname ; %} // Include the given header, where the class definition is found - %include + %include < ## classinclude ## > using nspace ##:: ## classname ; // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; %template( classname ) nspace ## :: ## tmplstring ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; %template(Vector ## classname) std::vector< nspace ## :: ## classname >; %enddef // // SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(classname, classinclude, nspace) // Include the include file in the generated cpp file %{ - #include < classinclude > + #include < ## classinclude ## > typedef nspace ## :: ## classname classname ## ; using nspace ## :: ## classname ; %} // Include the given header, where the class definition is found - %include + %include < ## classinclude ## > using nspace ##:: ## classname ; // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; %enddef diff --git a/Wrapping/Python/CMakeLists.txt b/Wrapping/Python/CMakeLists.txt index 99c6160c66..7c9c634fe6 100644 --- a/Wrapping/Python/CMakeLists.txt +++ b/Wrapping/Python/CMakeLists.txt @@ -1,77 +1,77 @@ # Version 2.8.1 is the minium requirement for this script. # this is lower than the general minimum requirement. #cmake_minimum_required ( VERSION 2.8.1 FATAL_ERROR ) include(mitkTargetLinkLibrariesWithDynamicLookup) project( MITK_Python ) set(CMAKE_SHARED_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) set(CMAKE_MODULE_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) mitk_check_dynamic_lookup(MODULE SHARED MITK_UNDEFINED_SYMBOLS_ALLOWED ) # # Find the necessary libraries etc.. # if ( MITK_UNDEFINED_SYMBOLS_ALLOWED ) set( _QUIET_LIBRARY "QUIET" ) else() set( _QUIET_LIBRARY "REQUIRED" ) endif() find_package ( PythonInterp REQUIRED ) find_package ( PythonLibs ${_QUIET_LIBRARY} ) include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ) # # Options # option ( MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) mark_as_advanced( MITK_PYTHON_THREADS ) option ( MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) mark_as_advanced( MITK_PYTHON_EGG ) option ( MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) mark_as_advanced( MITK_PYTHON_WHEEL ) # Prepare the SWIG-File, i.e. especially add necessary include folders -mitkSwigPrepareFiles(MITK.i "MitkCore;MitkCLCore;MitkCLUtilities") +mitkSwigPrepareFiles(MITK.i "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon") # Add additional SWIG Parameters # These parameters depend on the target language set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword ) if( MITK_PYTHON_THREADS ) set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} -threads) endif() set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) # Create the actual SWIG project swig_add_module(pyMITK python MITK.i ) -mitkSwigAddLibraryDependencies(pyMITK "MitkCore;MitkCLCore;MitkCLUtilities") +mitkSwigAddLibraryDependencies(pyMITK "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon") mitk_target_link_libraries_with_dynamic_lookup(${SWIG_MODULE_pyMITK_REAL_NAME} ${PYTHON_LIBRARIES}) if(DEFINED SKBUILD) message(WARNING "SKBuild exists") # Currently this installation install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pyMITK.py ${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py # ${MITK_DOC_FILES} DESTINATION pyMITK COMPONENT Runtime ) install(TARGETS ${SWIG_MODULE_pyMITK_REAL_NAME} RUNTIME DESTINATION pyMITK LIBRARY DESTINATION pyMITK COMPONENT Runtime ) else() message(WARNING "SKBuild missing") include(LegacyPackaging.cmake) endif() diff --git a/Wrapping/Python/mitkNumpyArrayConversion.cxx b/Wrapping/Python/mitkNumpyArrayConversion.cxx index 305045f93d..5e4b41cad3 100644 --- a/Wrapping/Python/mitkNumpyArrayConversion.cxx +++ b/Wrapping/Python/mitkNumpyArrayConversion.cxx @@ -1,234 +1,237 @@ /*========================================================================= * * Copyright Insight Software Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #include #include #include #include #include "mitkImage.h" // Python is written in C #ifdef __cplusplus extern "C" { #endif /** An internal function that returns a memoryview object to the * MITK Image's buffer (shallow). The correct copy and writing * policies need to be done by the end-user method. */ static PyObject * mitk_GetMemoryViewFromImage( PyObject *SWIGUNUSEDPARM(self), PyObject *args ) { const void * mitkBufferPtr; Py_ssize_t len; std::vector< unsigned int > size; size_t pixelSize = 1; unsigned int dimension; /* Cast over to a sitk Image. */ PyObject * pyImage; void * voidImage; mitk::Image * mitkImage; int res = 0; PyObject * memoryView = NULL; Py_buffer pyBuffer; memset(&pyBuffer, 0, sizeof(Py_buffer)); + unsigned int accumulatorValue = 1; if( !PyArg_ParseTuple( args, "O", &pyImage ) ) { SWIG_fail; // SWIG_fail is a macro that says goto: fail (return NULL) } res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 ); if (!SWIG_IsOK(res)) { mitk::Image::Pointer tmpImage; res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'"); } tmpImage = *(reinterpret_cast(voidImage)); voidImage = reinterpret_cast(tmpImage.GetPointer()); } mitkImage = reinterpret_cast< mitk::Image * >( voidImage ); mitkBufferPtr = mitkImage->GetData(); pixelSize = mitkImage->GetPixelType().GetBitsPerComponent() / 8; dimension = mitkImage->GetDimension(); for (int i = 0; i < dimension; ++i) { size.push_back(mitkImage->GetDimension(i)); } // if the image is a vector just treat is as another dimension if ( mitkImage->GetPixelType().GetNumberOfComponents() > 1 ) { size.push_back( mitkImage->GetPixelType().GetNumberOfComponents() ); } - len = std::accumulate( size.begin(), size.end(), unsigned int(1), std::multiplies() ); + len = std::accumulate( size.begin(), size.end(), accumulatorValue, std::multiplies() ); len *= pixelSize; if (PyBuffer_FillInfo(&pyBuffer, NULL, (void*)mitkBufferPtr, len, true, PyBUF_CONTIG_RO)!=0) { SWIG_fail; } memoryView = PyMemoryView_FromBuffer(&pyBuffer); PyBuffer_Release(&pyBuffer); return memoryView; fail: Py_XDECREF( memoryView ); return NULL; } /** An internal function that performs a deep copy of the image buffer * into a python byte array. The byte array can later be converted * into a numpy array with the frombuffer method. */ static PyObject* mitk_SetImageFromArray( PyObject *SWIGUNUSEDPARM(self), PyObject *args ) { PyObject * pyImage = NULL; const void *buffer; Py_ssize_t buffer_len; Py_buffer pyBuffer; memset(&pyBuffer, 0, sizeof(Py_buffer)); mitk::Image * mitkImage = NULL; void * mitkBufferPtr = NULL; size_t pixelSize = 1; unsigned int dimension = 0; std::vector< unsigned int > size; size_t len = 1; + unsigned int accuValue = 1; + // We wish to support both the new PEP3118 buffer interface and the // older. So we first try to parse the arguments with the new buffer // protocol, then the old. if (!PyArg_ParseTuple( args, "s*O", &pyBuffer, &pyImage ) ) { PyErr_Clear(); #ifdef PY_SSIZE_T_CLEAN typedef Py_ssize_t bufSizeType; #else typedef int bufSizeType; #endif bufSizeType _len; // This function takes 2 arguments from python, the first is an // python object which support the old "ReadBuffer" interface if( !PyArg_ParseTuple( args, "s#O", &buffer, &_len, &pyImage ) ) { return NULL; } buffer_len = _len; } else { if ( PyBuffer_IsContiguous( &pyBuffer, 'C' ) != 1 ) { PyBuffer_Release( &pyBuffer ); PyErr_SetString( PyExc_TypeError, "A C Contiguous buffer object is required." ); return NULL; } buffer_len = pyBuffer.len; buffer = pyBuffer.buf; } /* Cast over to a sitk Image. */ { void * voidImage; int res = 0; res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 ); if (!SWIG_IsOK(res)) { mitk::Image::Pointer tmpImage; res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'"); } tmpImage = *(reinterpret_cast(voidImage)); voidImage = reinterpret_cast(tmpImage.GetPointer()); } mitkImage = reinterpret_cast< mitk::Image * >(voidImage); } try { mitkBufferPtr = mitkImage->GetData(); pixelSize= mitkImage->GetPixelType().GetBitsPerComponent() / 8; } catch( const std::exception &e ) { std::string msg = "Exception thrown in MITK new Image: "; msg += e.what(); PyErr_SetString( PyExc_RuntimeError, msg.c_str() ); goto fail; } dimension = mitkImage->GetDimension(); for (int i = 0; i < dimension; ++i) { size.push_back(mitkImage->GetDimension(i)); } // if the image is a vector just treat is as another dimension if (mitkImage->GetPixelType().GetNumberOfComponents() > 1) { size.push_back(mitkImage->GetPixelType().GetNumberOfComponents()); } - len = std::accumulate(size.begin(), size.end(), unsigned int(1), std::multiplies()); + len = std::accumulate(size.begin(), size.end(), accuValue, std::multiplies()); len *= pixelSize; if ( buffer_len != len ) { PyErr_SetString( PyExc_RuntimeError, "Size mismatch of image and Buffer." ); goto fail; } memcpy( (void *)mitkBufferPtr, buffer, len ); PyBuffer_Release( &pyBuffer ); Py_RETURN_NONE; fail: PyBuffer_Release( &pyBuffer ); return NULL; } #ifdef __cplusplus } // end extern "C" #endif