void ToMayaImageConverter::writeChannel( MImage &image, typename TypedData< std::vector<T> >::Ptr channelData, unsigned channelOffset, unsigned numChannels ) const
{
	assert( channelOffset < numChannels );

	ConstImagePrimitivePtr toConvert = runTimeCast<const ImagePrimitive>( srcParameter()->getValidatedValue() );
	assert( toConvert );

	unsigned width, height;
	image.getSize( width, height );

	const Imath::Box2i &dataWindow = toConvert->getDataWindow();
	const Imath::Box2i &displayWindow = toConvert->getDisplayWindow();

	unsigned int dataWidth = dataWindow.size().x + 1;
	unsigned int dataHeight = dataWindow.size().y + 1;

	Imath::V2i dataOffset = dataWindow.min - displayWindow.min ;

	boost::multi_array_ref< const T, 2 > src( &channelData->readable()[0], boost::extents[dataHeight][dataWidth] );
	boost::multi_array_ref< T, 3 > dst( MImageAccessor<T>::getPixels( image ), boost::extents[ height ][ width ][ numChannels ] );

	for ( unsigned x = 0; x < dataWidth; x++ )
	{
		for ( unsigned y = 0; y < dataHeight; y++ )
		{
			/// Vertical flip, to match Maya
			dst[ ( height - 1 ) - ( y + dataOffset.y ) ][ x + dataOffset.x ][channelOffset] = src[y][x];
		}
	}
}
typename TypedData< std::vector< U > >::Ptr vectorLookup( Lookup<T,U> &lookup, typename TypedData< std::vector< T > >::Ptr x )
{
	typename TypedData< std::vector< U > >::Ptr res = new TypedData< std::vector< U > >;
	res->writable().resize( x->readable().size() );
	typename std::vector< T >::const_iterator xIt = x->readable().begin();
	typename std::vector< U >::iterator yIt = res->writable().begin();

	for ( ; xIt != x->readable().end(); xIt++, yIt++ )
	{
		*yIt = lookup( *xIt );
	}
	return res;
}
static void triangulate( T &t, typename TypedData<std::vector<typename T::Point> >::ConstPtr p )
{
	t.triangulate( p->readable().begin(), p->readable().end() );
}
DataPtr SGIImageReader::readTypedChannel( const std::string &name, const Box2i &dataWindow )
{
	typedef TypedData< std::vector< V > > TargetVector;

	assert( open() );

	assert( m_header );

	typename TypedData< std::vector<T > >::ConstPtr dataBuffer = assertedStaticCast< TypedData< std::vector<T > > >( m_buffer );
	assert( dataBuffer );

	const typename TypedData< std::vector<T > >::ValueType &buffer = dataBuffer->readable();

	assert( m_header->m_channelOffsets.find( name ) != m_header->m_channelOffsets.end() );
	int channelOffset = m_header->m_channelOffsets[name];

	typename TargetVector::Ptr dataContainer = new TargetVector();

	typename TargetVector::ValueType &data = dataContainer->writable();
	int area = ( dataWindow.size().x + 1 ) * ( dataWindow.size().y + 1 );
	assert( area >= 0 );
	data.resize( area );

	int dataWidth = 1 + dataWindow.size().x;

	Box2i wholeDataWindow = this->dataWindow();

	int wholeDataHeight = 1 + wholeDataWindow.size().y;
	int wholeDataWidth = 1 + wholeDataWindow.size().x;

	const int yMin = dataWindow.min.y - wholeDataWindow.min.y;
	const int yMax = dataWindow.max.y - wholeDataWindow.min.y;

	const int xMin = dataWindow.min.x - wholeDataWindow.min.x;
	const int xMax = dataWindow.max.x - wholeDataWindow.min.x;

	ScaledDataConversion<T, V> converter;

	if ( m_header->m_fileHeader.m_storageFormat >= 1 ) /// RLE
	{
		int dataY = 0;
		for ( int y = yMin ; y <= yMax ; ++y, ++dataY )
		{
			assert( yMin >= 0 );
			assert( yMin < wholeDataHeight );

			/// Images are unencoded "upside down" (flipped in Y), for our purposes
			uint32_t rowOffset = m_header->m_offsetTable[ channelOffset * wholeDataHeight + ( wholeDataHeight - 1 - y ) ];

			if ( rowOffset >= buffer.size() )
			{
				throw IOException( "SGIImageReader: Invalid RLE row offset found while reading " + fileName() );
			}

			std::vector<T> scanline( wholeDataWidth );

			uint32_t scanlineOffset = 0;
			bool done = false;

			while ( !done )
			{
				T pixel = buffer[ rowOffset ++ ];

				T count = pixel & 0x7f;

				if ( count == 0 )
				{
					done = true;
				}
				else
				{
					if ( pixel & 0x80 )
					{
						if ( scanlineOffset + count - 1 >= scanline.size() || rowOffset + count - 1 >= buffer.size() )
						{
							throw IOException( "SGIImageReader: Invalid RLE data found while reading " + fileName() );
						}

						while ( count -- )
						{
							assert( scanlineOffset < scanline.size() );
							assert( rowOffset < buffer.size() );
							scanline[ scanlineOffset++ ] = buffer[ rowOffset ++ ];
						}
					}
					else
					{
						if ( scanlineOffset + count - 1 >= scanline.size() || rowOffset - 1 >= buffer.size() )
						{
							throw IOException( "SGIImageReader: Invalid RLE data found while reading " + fileName() );
						}

						assert( rowOffset < buffer.size() );
						pixel = buffer[ rowOffset ++ ];

						while ( count -- )
						{
							assert( scanlineOffset < scanline.size() );
							scanline[ scanlineOffset++ ] = pixel;
						}
					}
				}
			}

			if ( scanlineOffset != scanline.size() )
			{
				throw IOException( "SGIImageReader: Error occurred during RLE decode while reading " + fileName() );
			}

			int dataOffset = dataY * dataWidth;

			for ( int x = xMin; x <= xMax ; ++x, ++dataOffset  )
			{
				data[dataOffset] = converter( scanline[x] );
			}
		}
	}
	else /// Not RLE
	{
		int dataY = 0;

		for ( int y = dataWindow.min.y; y <= dataWindow.max.y; ++y, ++dataY )
		{
			typename TargetVector::ValueType::size_type dataOffset = dataY * dataWidth;

			for ( int x = dataWindow.min.x; x <= dataWindow.max.x; ++x, ++dataOffset )
			{
				assert( dataOffset < data.size() );

				/// Images are unencoded "upside down" (flipped in Y), for our purposes
				data[dataOffset] = converter( buffer[ ( channelOffset * wholeDataHeight * wholeDataWidth ) + ( wholeDataHeight - 1 - y  ) * wholeDataWidth + x  ] );
			}
		}
	}

	return dataContainer;
}