text: /*=========================================================================
  *
  *  Copyright NumFOCUS
  *
  *  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 <string.h>
  
  #include <numeric>
  #include <functional>
  
  #include "sitkImage.h"
  #include "sitkConditional.h"
  #include "sitkExceptionObject.h"
  
  namespace sitk = itk::simple;
  
  // Python is written in C
  #ifdef __cplusplus
  extern "C"
  {
  #endif
  
  /** An internal function that returns a memoryview object to the
   * SimpleITK Image's buffer (shallow). The correct copy and writing
   * policies need to be done by the end-user method.
   */
  static PyObject *
  sitk_GetMemoryViewFromImage( PyObject *SWIGUNUSEDPARM(self), PyObject *args )
  {
    const void *                sitkBufferPtr;
    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;
    sitk::Image *               sitkImage;
    int                         res           = 0;
  
    PyObject *                  memoryView    = NULL;
    Py_buffer                   pyBuffer;
    memset(&pyBuffer, 0, sizeof(Py_buffer));
  
  
    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_itk__simple__Image, 0 );
    if( !SWIG_IsOK( res ) )
      {
      SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'");
      }
    sitkImage = reinterpret_cast< sitk::Image * >( voidImage );
  
    switch( sitkImage->GetPixelIDValue() )
      {
    case sitk::sitkUnknown:
      PyErr_SetString( PyExc_RuntimeError, "Unknown pixel type." );
      SWIG_fail;
      break;
    case sitk::ConditionalValue< sitk::sitkVectorUInt8 != sitk::sitkUnknown, sitk::sitkVectorUInt8, -14 >::Value:
    case sitk::ConditionalValue< sitk::sitkUInt8 != sitk::sitkUnknown, sitk::sitkUInt8, -2 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsUInt8();
      pixelSize  = sizeof( uint8_t );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorInt8 != sitk::sitkUnknown, sitk::sitkVectorInt8, -15 >::Value:
    case sitk::ConditionalValue< sitk::sitkInt8 != sitk::sitkUnknown, sitk::sitkInt8, -3 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsInt8();
      pixelSize  = sizeof( int8_t );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorUInt16 != sitk::sitkUnknown, sitk::sitkVectorUInt16, -16 >::Value:
    case sitk::ConditionalValue< sitk::sitkUInt16 != sitk::sitkUnknown, sitk::sitkUInt16, -4 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsUInt16();
      pixelSize  = sizeof( uint16_t );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorInt16 != sitk::sitkUnknown, sitk::sitkVectorInt16, -17 >::Value:
    case sitk::ConditionalValue< sitk::sitkInt16 != sitk::sitkUnknown, sitk::sitkInt16, -5 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsInt16();
      pixelSize  = sizeof( int16_t );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorUInt32 != sitk::sitkUnknown, sitk::sitkVectorUInt32, -18 >::Value:
    case sitk::ConditionalValue< sitk::sitkUInt32 != sitk::sitkUnknown, sitk::sitkUInt32, -6 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsUInt32();
      pixelSize  = sizeof( uint32_t );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorInt32 != sitk::sitkUnknown, sitk::sitkVectorInt32, -19 >::Value:
    case sitk::ConditionalValue< sitk::sitkInt32 != sitk::sitkUnknown, sitk::sitkInt32, -7 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsInt32();
      pixelSize  = sizeof( int32_t );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorUInt64 != sitk::sitkUnknown, sitk::sitkVectorUInt64, -20 >::Value:
    case sitk::ConditionalValue< sitk::sitkUInt64 != sitk::sitkUnknown, sitk::sitkUInt64, -8 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsUInt64();
      pixelSize  = sizeof( uint64_t );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorInt64 != sitk::sitkUnknown, sitk::sitkVectorInt64, -21 >::Value:
    case sitk::ConditionalValue< sitk::sitkInt64 != sitk::sitkUnknown, sitk::sitkInt64, -9 >::Value:
       sitkBufferPtr = (const void *)sitkImage->GetBufferAsInt64();
       pixelSize  = sizeof( int64_t );
       break;
    case sitk::ConditionalValue< sitk::sitkVectorFloat32 != sitk::sitkUnknown, sitk::sitkVectorFloat32, -22 >::Value:
    case sitk::ConditionalValue< sitk::sitkFloat32 != sitk::sitkUnknown, sitk::sitkFloat32, -10 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsFloat();
      pixelSize  = sizeof( float );
      break;
    case sitk::ConditionalValue< sitk::sitkVectorFloat64 != sitk::sitkUnknown, sitk::sitkVectorFloat64, -23 >::Value:
    case sitk::ConditionalValue< sitk::sitkFloat64 != sitk::sitkUnknown, sitk::sitkFloat64, -11 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsDouble(); // \todo rename to Float64 for consistency
      pixelSize  = sizeof( double );
      break;
    case sitk::ConditionalValue< sitk::sitkComplexFloat32 != sitk::sitkUnknown, sitk::sitkComplexFloat32, -12 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsFloat();
      pixelSize  = 2*sizeof( float );
      break;
    case sitk::ConditionalValue< sitk::sitkComplexFloat64 != sitk::sitkUnknown, sitk::sitkComplexFloat64, -13 >::Value:
      sitkBufferPtr = (const void *)sitkImage->GetBufferAsDouble();
      pixelSize  = 2*sizeof( double );
      break;
    default:
      PyErr_SetString( PyExc_RuntimeError, "Unknown pixel type." );
      SWIG_fail;
      }
  
    dimension = sitkImage->GetDimension();
    size = sitkImage->GetSize();
  
    // if the image is a vector just treat is as another dimension
    if ( sitkImage->GetNumberOfComponentsPerPixel() > 1 )
      {
      size.push_back( sitkImage->GetNumberOfComponentsPerPixel() );
      }
  
    len = std::accumulate( size.begin(), size.end(), size_t(1), std::multiplies<size_t>() );
    len *= pixelSize;
  
    if (PyBuffer_FillInfo(&pyBuffer, NULL, (void*)sitkBufferPtr, 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*
  sitk_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));
  
    const sitk::Image * sitkImage = NULL;
    void * sitkBufferPtr = NULL;
    size_t pixelSize = 1;
  
    unsigned int dimension = 0;
    std::vector< unsigned int > size;
    size_t len = 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_itk__simple__Image, 0 );
      if( !SWIG_IsOK( res ) )
        {
        SWIG_exception_fail(SWIG_ArgError(res), "in method 'SetImageFromArray', argument needs to be of type 'sitk::Image *'");
        }
      sitkImage = reinterpret_cast< sitk::Image * >( voidImage );
    }
  
    try
      {
      switch( sitkImage->GetPixelIDValue() )
        {
        case sitk::sitkUnknown:
          PyErr_SetString( PyExc_RuntimeError, "Unknown pixel type." );
          goto fail;
          break;
        case sitk::ConditionalValue< sitk::sitkVectorUInt8 != sitk::sitkUnknown, sitk::sitkVectorUInt8, -14 >::Value:
        case sitk::ConditionalValue< sitk::sitkUInt8 != sitk::sitkUnknown, sitk::sitkUInt8, -2 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsUInt8();
          pixelSize  = sizeof( uint8_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorInt8 != sitk::sitkUnknown, sitk::sitkVectorInt8, -15 >::Value:
        case sitk::ConditionalValue< sitk::sitkInt8 != sitk::sitkUnknown, sitk::sitkInt8, -3 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsInt8();
          pixelSize  = sizeof( int8_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorUInt16 != sitk::sitkUnknown, sitk::sitkVectorUInt16, -16 >::Value:
        case sitk::ConditionalValue< sitk::sitkUInt16 != sitk::sitkUnknown, sitk::sitkUInt16, -4 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsUInt16();
          pixelSize  = sizeof( uint16_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorInt16 != sitk::sitkUnknown, sitk::sitkVectorInt16, -17 >::Value:
        case sitk::ConditionalValue< sitk::sitkInt16 != sitk::sitkUnknown, sitk::sitkInt16, -5 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsInt16();
          pixelSize  = sizeof( int16_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorUInt32 != sitk::sitkUnknown, sitk::sitkVectorUInt32, -18 >::Value:
        case sitk::ConditionalValue< sitk::sitkUInt32 != sitk::sitkUnknown, sitk::sitkUInt32, -6 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsUInt32();
          pixelSize  = sizeof( uint32_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorInt32 != sitk::sitkUnknown, sitk::sitkVectorInt32, -19 >::Value:
        case sitk::ConditionalValue< sitk::sitkInt32 != sitk::sitkUnknown, sitk::sitkInt32, -7 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsInt32();
          pixelSize  = sizeof( int32_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorUInt64 != sitk::sitkUnknown, sitk::sitkVectorUInt64, -20 >::Value:
        case sitk::ConditionalValue< sitk::sitkUInt64 != sitk::sitkUnknown, sitk::sitkUInt64, -8 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsUInt64();
          pixelSize  = sizeof( uint64_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorInt64 != sitk::sitkUnknown, sitk::sitkVectorInt64, -21 >::Value:
        case sitk::ConditionalValue< sitk::sitkInt64 != sitk::sitkUnknown, sitk::sitkInt64, -9 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsInt64();
          pixelSize  = sizeof( int64_t );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorFloat32 != sitk::sitkUnknown, sitk::sitkVectorFloat32, -22 >::Value:
        case sitk::ConditionalValue< sitk::sitkFloat32 != sitk::sitkUnknown, sitk::sitkFloat32, -10 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsFloat();
          pixelSize  = sizeof( float );
          break;
        case sitk::ConditionalValue< sitk::sitkVectorFloat64 != sitk::sitkUnknown, sitk::sitkVectorFloat64, -23 >::Value:
        case sitk::ConditionalValue< sitk::sitkFloat64 != sitk::sitkUnknown, sitk::sitkFloat64, -11 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsDouble(); // \todo rename to Float64 for consistency
          pixelSize  = sizeof( double );
          break;
        case sitk::ConditionalValue< sitk::sitkComplexFloat32 != sitk::sitkUnknown, sitk::sitkComplexFloat32, -12 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsFloat();
          pixelSize  = 2*sizeof( float );
          break;
        case sitk::ConditionalValue< sitk::sitkComplexFloat64 != sitk::sitkUnknown, sitk::sitkComplexFloat64, -13 >::Value:
          sitkBufferPtr = (void *)sitkImage->GetBufferAsDouble();
          pixelSize  = 2*sizeof( double );
          break;
        default:
          PyErr_SetString( PyExc_RuntimeError, "Unknown pixel type." );
          goto fail;
        }
      }
    catch( const std::exception &e )
      {
      std::string msg = "Exception thrown in SimpleITK new Image: ";
      msg += e.what();
      PyErr_SetString( PyExc_RuntimeError, msg.c_str() );
      goto fail;
      }
  
  
    dimension = sitkImage->GetDimension();
    size = sitkImage->GetSize();
  
    // if the image is a vector just treat is as another dimension
    if ( sitkImage->GetNumberOfComponentsPerPixel() > 1 )
      {
      size.push_back( sitkImage->GetNumberOfComponentsPerPixel() );
      }
  
    len = std::accumulate( size.begin(), size.end(), size_t(1), std::multiplies<size_t>() );
    len *= pixelSize;
  
    if ( buffer_len != len )
      {
      PyErr_SetString( PyExc_RuntimeError, "Size mismatch of image and Buffer." );
      goto fail;
      }
  
    memcpy( (void *)sitkBufferPtr, buffer, len );
  
  
    PyBuffer_Release( &pyBuffer );
    Py_RETURN_NONE;
  
  fail:
    PyBuffer_Release( &pyBuffer );
    return NULL;
  }
  
  #ifdef __cplusplus
  } // end extern "C"
  #endif
  