From 43b16d85f4fa6fd5a42168dbe6e3bbef86cbf14f Mon Sep 17 00:00:00 2001 From: castano Date: Sat, 2 Apr 2011 07:41:55 +0000 Subject: [PATCH] Use STB image by default. Add buffer object, try to reduce binary size. --- src/CMakeLists.txt | 9 +- src/nvconfig.h.in | 11 +- src/nvcore/Array.h | 295 ++++---- src/nvcore/CMakeLists.txt | 4 +- src/nvcore/TextReader.cpp | 2 +- src/nvimage/FloatImage.cpp | 4 +- src/nvimage/ImageIO.cpp | 1460 ++++++++++++++++++------------------ 7 files changed, 916 insertions(+), 869 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cf41aa5..1e72b65 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${NV_SOURCE_DIR}/extern/poshlib) +INCLUDE_DIRECTORIES(${NV_SOURCE_DIR}/extern/stb) SUBDIRS(nvcore) SUBDIRS(nvmath) @@ -81,7 +82,7 @@ ELSE(FREEIMAGE_FOUND) ENDIF(FREEIMAGE_FOUND) # JPEG -INCLUDE(FindJPEG) +#INCLUDE(FindJPEG) IF(JPEG_FOUND) SET(HAVE_JPEG ${JPEG_FOUND} CACHE BOOL "Set to TRUE if JPEG is found, FALSE otherwise") MESSAGE(STATUS "Looking for JPEG - found") @@ -90,7 +91,7 @@ ELSE(JPEG_FOUND) ENDIF(JPEG_FOUND) # PNG -INCLUDE(FindPNG) +#INCLUDE(FindPNG) IF(PNG_FOUND) SET(HAVE_PNG ${PNG_FOUND} CACHE BOOL "Set to TRUE if PNG is found, FALSE otherwise") MESSAGE(STATUS "Looking for PNG - found") @@ -99,7 +100,7 @@ ELSE(PNG_FOUND) ENDIF(PNG_FOUND) # TIFF -SET(TIFF_NAMES libtiff) +#SET(TIFF_NAMES libtiff) INCLUDE(FindTIFF) IF(TIFF_FOUND) SET(HAVE_TIFF ${TIFF_FOUND} CACHE BOOL "Set to TRUE if TIFF is found, FALSE otherwise") @@ -109,7 +110,7 @@ ELSE(TIFF_FOUND) ENDIF(TIFF_FOUND) # OpenEXR -INCLUDE(${NV_CMAKE_DIR}/FindOpenEXR.cmake) +#INCLUDE(${NV_CMAKE_DIR}/FindOpenEXR.cmake) IF(OPENEXR_FOUND) SET(HAVE_OPENEXR ${OPENEXR_FOUND} CACHE BOOL "Set to TRUE if OpenEXR is found, FALSE otherwise") MESSAGE(STATUS "Looking for OpenEXR - found") diff --git a/src/nvconfig.h.in b/src/nvconfig.h.in index 0142d96..16da646 100644 --- a/src/nvconfig.h.in +++ b/src/nvconfig.h.in @@ -10,11 +10,12 @@ #cmakedefine HAVE_OPENMP #cmakedefine HAVE_DISPATCH_H -#cmakedefine HAVE_PNG -#cmakedefine HAVE_JPEG -#cmakedefine HAVE_TIFF -#cmakedefine HAVE_OPENEXR -#cmakedefine HAVE_FREEIMAGE +#define HAVE_STBIMAGE +//#cmakedefine HAVE_PNG +//#cmakedefine HAVE_JPEG +//#cmakedefine HAVE_TIFF +//#cmakedefine HAVE_OPENEXR +//#cmakedefine HAVE_FREEIMAGE #cmakedefine HAVE_MAYA diff --git a/src/nvcore/Array.h b/src/nvcore/Array.h index 73905df..0530553 100644 --- a/src/nvcore/Array.h +++ b/src/nvcore/Array.h @@ -6,7 +6,8 @@ /* This array class requires the elements to be relocable; it uses memmove and realloc. Ideally I should be -using swap, but I honestly don't care. +using swap, but I honestly don't care. The only thing that you should be aware of is that internal pointers +are not supported. The foreach macros that I use are very non-standard and somewhat confusing. It would be nice to have standard foreach as in Qt. @@ -37,6 +38,94 @@ namespace nv } } + template + void construct(T * ptr, uint count) { + for (uint i = 0; i < count; i++) { + new(ptr+i) T; // placement new + } + } + + template + void destroy(T * ptr, uint count) { + for (uint i = 0; i < count; i++) { + (ptr+i)->~T(); + } + } + + template + void fill(T * restrict dst, const T & value, uint count) { + for (uint i = 0; i < count; i++) { + dst[i] = value; + } + } + + template + void copy(T * restrict dst, const T * restrict src, uint count) { + for (uint i = 0; i < count; i++) { + dst[i] = src[i]; + } + } + + + class Buffer + { + NV_FORBID_COPY(Buffer) + public: + // Ctor. + Buffer() : m_buffer(NULL), m_buffer_size(0), m_size(0) + { + } + + // Dtor. + ~Buffer() { + allocate(0, 0); + } + + + // Get vector size. + NV_FORCEINLINE uint size() const { return m_size; } + + // Get vector size. + NV_FORCEINLINE uint count() const { return m_size; } + + // Is a null vector. + NV_FORCEINLINE bool isNull() const { return m_buffer == NULL; } + + + // Swap the members of this vector and the given vector. + friend void swap(Buffer & a, Buffer & b) + { + swap(a.m_buffer, b.m_buffer); + swap(a.m_buffer_size, b.m_buffer_size); + swap(a.m_size, b.m_size); + } + + protected: + + /// Change buffer size. + NV_NOINLINE void allocate(uint count, uint size) + { + if (count == 0) { + // free the buffer. + if (m_buffer != NULL) { + ::free(m_buffer); + m_buffer = NULL; + } + } + else { + // realloc the buffer + m_buffer = ::realloc(m_buffer, count * size); + } + + m_buffer_size = count; + } + + + protected: + void * m_buffer; + uint m_buffer_size; + uint m_size; + }; /** @@ -44,38 +133,30 @@ namespace nv * some nice foreach enumerators. */ template - class NVCORE_CLASS Array { + class NVCORE_CLASS Array : public Buffer { public: - /// Ctor. - Array() : m_buffer(NULL), m_size(0), m_buffer_size(0) - { - } + // Default constructor. + NV_FORCEINLINE Array() : Buffer() {} - /// Copy ctor. - Array( const Array & a ) : m_buffer(NULL), m_size(0), m_buffer_size(0) - { - copy(a.m_buffer, a.m_size); + // Copy constructor. + NV_FORCEINLINE Array(const Array & a) : Buffer() { + copy(a.buffer(), a.m_size); } - /// Ctor that initializes the vector with the given elements. - Array( const T * ptr, int num ) : m_buffer(NULL), m_size(0), m_buffer_size(0) - { + // Constructor that initializes the vector with the given elements. + NV_FORCEINLINE Array(const T * ptr, int num) : Buffer() { copy(ptr, num); } - /// Allocate array. - explicit Array(uint capacity) : m_buffer(NULL), m_size(0), m_buffer_size(0) - { + // Allocate array. + NV_FORCEINLINE explicit Array(uint capacity) : Buffer() { allocate(capacity); } - - /// Dtor. - ~Array() - { + // Destructor. + NV_FORCEINLINE ~Array() { clear(); - allocate(0); } @@ -83,24 +164,24 @@ namespace nv NV_FORCEINLINE const T & operator[]( uint index ) const { nvDebugCheck(index < m_size); - return m_buffer[index]; + return buffer()[index]; } NV_FORCEINLINE const T & at( uint index ) const { nvDebugCheck(index < m_size); - return m_buffer[index]; + return buffer()[index]; } /// Element access. NV_FORCEINLINE T & operator[] ( uint index ) { nvDebugCheck(index < m_size); - return m_buffer[index]; + return buffer()[index]; } NV_FORCEINLINE T & at( uint index ) { nvDebugCheck(index < m_size); - return m_buffer[index]; + return buffer()[index]; } /// Get vector size. @@ -110,16 +191,16 @@ namespace nv NV_FORCEINLINE uint count() const { return m_size; } /// Get const vector pointer. - NV_FORCEINLINE const T * buffer() const { return m_buffer; } + NV_FORCEINLINE const T * buffer() const { return (const T *)m_buffer; } /// Get vector pointer. - NV_FORCEINLINE T * mutableBuffer() { return m_buffer; } + NV_FORCEINLINE T * buffer() { return (T *)m_buffer; } /// Is vector empty. NV_FORCEINLINE bool isEmpty() const { return m_size == 0; } /// Is a null vector. - NV_FORCEINLINE bool isNull() const { return m_buffer == NULL; } + NV_FORCEINLINE bool isNull() const { return m_buffer == NULL; } /// Push an element at the end of the vector. @@ -131,12 +212,12 @@ namespace nv { const T copy(val); // create a copy in case value is inside of this array. resize(new_size); - m_buffer[new_size-1] = copy; + buffer()[new_size-1] = copy; } else { m_size = new_size; - new(m_buffer+new_size-1) T(val); + new(buffer()+new_size-1) T(val); } } NV_FORCEINLINE void pushBack( const T & val ) @@ -155,8 +236,8 @@ namespace nv return *this; } - /// Pop and return element at the end of the vector. - void pop_back() + /// Pop the element at the end of the vector. + NV_FORCEINLINE void pop_back() { nvDebugCheck( m_size > 0 ); resize( m_size - 1 ); @@ -170,28 +251,28 @@ namespace nv NV_FORCEINLINE const T & back() const { nvDebugCheck( m_size > 0 ); - return m_buffer[m_size-1]; + return buffer()[m_size-1]; } /// Get back element. NV_FORCEINLINE T & back() { nvDebugCheck( m_size > 0 ); - return m_buffer[m_size-1]; + return buffer()[m_size-1]; } /// Get front element. NV_FORCEINLINE const T & front() const { nvDebugCheck( m_size > 0 ); - return m_buffer[0]; + return buffer()[0]; } /// Get front element. NV_FORCEINLINE T & front() { nvDebugCheck( m_size > 0 ); - return m_buffer[0]; + return buffer()[0]; } /// Return true if element found. @@ -204,7 +285,7 @@ namespace nv bool find(const T & element, uint first, uint count, uint * index) const { for (uint i = first; i < first+count; i++) { - if (m_buffer[i] == element) { + if (buffer()[i] == element) { if (index != NULL) *index = i; return true; } @@ -219,17 +300,17 @@ namespace nv } /// Remove the element at the given index. This is an expensive operation! - void removeAt( uint index ) + void removeAt(uint index) { nvCheck(index >= 0 && index < m_size); - if( m_size == 1 ) { + if (m_size == 1) { clear(); } else { - m_buffer[index].~T(); + buffer()[index].~T(); - memmove( m_buffer+index, m_buffer+index+1, sizeof(T) * (m_size - 1 - index) ); + memmove(buffer()+index, buffer()+index+1, sizeof(T) * (m_size - 1 - index)); m_size--; } } @@ -246,35 +327,35 @@ namespace nv } /// Insert the given element at the given index shifting all the elements up. - void insertAt( uint index, const T & val = T() ) + void insertAt(uint index, const T & val = T()) { nvCheck( index >= 0 && index <= m_size ); resize( m_size + 1 ); - if( index < m_size - 1 ) { - memmove( m_buffer+index+1, m_buffer+index, sizeof(T) * (m_size - 1 - index) ); + if (index < m_size - 1) { + memmove(buffer()+index+1, buffer()+index, sizeof(T) * (m_size - 1 - index)); } // Copy-construct into the newly opened slot. - new(m_buffer+index) T(val); + new(buffer()+index) T(val); } /// Append the given data to our vector. NV_FORCEINLINE void append(const Array & other) { - append(other.m_buffer, other.m_size); + append(other.buffer(), other.m_size); } /// Append the given data to our vector. void append(const T other[], uint count) { - if( count > 0 ) { + if (count > 0) { const uint old_size = m_size; resize(m_size + count); // Must use operator=() to copy elements, in case of side effects (e.g. ref-counting). - for( uint i = 0; i < count; i++ ) { - m_buffer[old_size + i] = other[i]; + for (uint i = 0; i < count; i++ ) { + buffer()[old_size + i] = other[i]; } } } @@ -284,9 +365,8 @@ namespace nv void replaceWithLast(uint index) { nvDebugCheck( index < m_size ); - nv::swap(m_buffer[index], back()); - //m_buffer[index] = back(); - (m_buffer+m_size-1)->~T(); + nv::swap(buffer()[index], back()); + (buffer()+m_size-1)->~T(); m_size--; } @@ -294,38 +374,33 @@ namespace nv /// Resize the vector preserving existing elements. NV_NOINLINE void resize(uint new_size) { - uint i; uint old_size = m_size; m_size = new_size; + // @@ Use nv::destruct(...) // Destruct old elements (if we're shrinking). - for( i = new_size; i < old_size; i++ ) { - (m_buffer+i)->~T(); // Explicit call to the destructor + for (uint i = new_size; i < old_size; i++) { + (buffer()+i)->~T(); // Explicit call to the destructor } - if( m_size == 0 ) { - //allocate(0); // Don't shrink automatically. - } - else if( m_size <= m_buffer_size/* && m_size > m_buffer_size >> 1*/) { - // don't compact yet. - nvDebugCheck(m_buffer != NULL); - } - else { + // @@ Move allocation logic to Buffer::allocate + if (new_size > m_buffer_size) { uint new_buffer_size; - if( m_buffer_size == 0 ) { + if (m_buffer_size == 0) { // first allocation - new_buffer_size = m_size; + new_buffer_size = new_size; } else { // growing - new_buffer_size = m_size + (m_size >> 2); + new_buffer_size = new_size + (new_size >> 2); } allocate( new_buffer_size ); } + // @@ Use nv::construct(...) // Call default constructors - for( i = old_size; i < new_size; i++ ) { - new(m_buffer+i) T; // placement new + for (uint i = old_size; i < new_size; i++) { + new(buffer()+i) T; // placement new } } @@ -334,24 +409,19 @@ namespace nv /// new ones with the given value. NV_NOINLINE void resize( uint new_size, const T &elem ) { - uint i; uint old_size = m_size; m_size = new_size; + // @@ Use nv::destruct(...) // Destruct old elements (if we're shrinking). - for( i = new_size; i < old_size; i++ ) { - (m_buffer+i)->~T(); // Explicit call to the destructor + for (uint i = new_size; i < old_size; i++ ) { + (buffer()+i)->~T(); // Explicit call to the destructor } - if( m_size == 0 ) { - //allocate(0); // Don't shrink automatically. - } - else if( m_size <= m_buffer_size && m_size > m_buffer_size >> 1 ) { - // don't compact yet. - } - else { + // @@ Move allocation logic to Buffer::allocate + if (new_size > m_buffer_size) { uint new_buffer_size; - if( m_buffer_size == 0 ) { + if (m_buffer_size == 0) { // first allocation new_buffer_size = m_size; } @@ -362,9 +432,10 @@ namespace nv allocate( new_buffer_size ); } + // @@ Use nv::fill(...) // Call copy constructors - for( i = old_size; i < new_size; i++ ) { - new(m_buffer+i) T( elem ); // placement new + for (uint i = old_size; i < new_size; i++ ) { + new(buffer()+i) T( elem ); // placement new } } @@ -386,39 +457,37 @@ namespace nv NV_FORCEINLINE void reserve(uint desired_size) { if (desired_size > m_buffer_size) { - allocate( desired_size ); + allocate(desired_size); } } /// Copy elements to this array. Resizes it if needed. - void copy(const T * ptr, uint num) + NV_FORCEINLINE void copy(const T * ptr, uint num) { resize( num ); - for (uint i = 0; i < m_size; i++) { - m_buffer[i] = ptr[i]; - } + ::nv::copy(buffer(), ptr, num); } /// Assignment operator. NV_FORCEINLINE Array & operator=( const Array & a ) { - copy(a.m_buffer, a.m_size); + copy(a.buffer(), a.m_size); return *this; } // Release ownership of allocated memory and returns pointer to it. T * release() { - T * tmp = m_buffer; + T * tmp = buffer(); m_buffer = NULL; - m_size = 0; m_buffer_size = 0; + m_size = 0; return tmp; } /// Array serialization. friend Stream & operator<< ( Stream & s, Array & p ) { - if( s.isLoading() ) { + if (s.isLoading()) { uint size; s << size; p.resize( size ); @@ -427,8 +496,8 @@ namespace nv s << p.m_size; } - for( uint i = 0; i < p.m_size; i++ ) { - s << p.m_buffer[i]; + for (uint i = 0; i < p.m_size; i++) { + s << buffer()[i]; } return s; @@ -439,54 +508,24 @@ namespace nv typedef uint PseudoIndex; NV_FORCEINLINE PseudoIndex start() const { return 0; } - NV_FORCEINLINE bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); return i == this->m_size; }; + NV_FORCEINLINE bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); return i == this->m_size; } NV_FORCEINLINE void advance(PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); i++; } #if NV_CC_MSVC NV_FORCEINLINE T & operator[]( const PseudoIndexWrapper & i ) { - return m_buffer[i(this)]; + return at(i(this)); } NV_FORCEINLINE const T & operator[]( const PseudoIndexWrapper & i ) const { - return m_buffer[i(this)]; + return at(i(this)); } #endif +protected: - /// Swap the members of this vector and the given vector. - friend void swap(Array & a, Array & b) - { - swap(a.m_buffer, b.m_buffer); - swap(a.m_size, b.m_size); - swap(a.m_buffer_size, b.m_buffer_size); + NV_FORCEINLINE void allocate(uint count) { + Buffer::allocate(count, sizeof(T)); } - - private: - - /// Change buffer size. - NV_NOINLINE void allocate( uint rsize ) - { - m_buffer_size = rsize; - - // free the buffer. - if (m_buffer_size == 0) { - if (m_buffer) { - free( m_buffer ); - m_buffer = NULL; - } - } - - // realloc the buffer - else { - m_buffer = realloc(m_buffer, m_buffer_size); - } - } - - - private: - T * m_buffer; - uint m_size; - uint m_buffer_size; }; } // nv namespace diff --git a/src/nvcore/CMakeLists.txt b/src/nvcore/CMakeLists.txt index 5840b11..3070340 100644 --- a/src/nvcore/CMakeLists.txt +++ b/src/nvcore/CMakeLists.txt @@ -9,8 +9,8 @@ SET(CORE_SRCS DefsGnucWin32.h DefsVcWin32.h FileSystem.h FileSystem.cpp - ForEach.h - HashMap.h + ForEach.h + HashMap.h Library.h Library.cpp Memory.h Memory.cpp Ptr.h diff --git a/src/nvcore/TextReader.cpp b/src/nvcore/TextReader.cpp index fac55de..2ffb8dd 100644 --- a/src/nvcore/TextReader.cpp +++ b/src/nvcore/TextReader.cpp @@ -48,7 +48,7 @@ const char * TextReader::readToEnd() m_text.reserve(size + 1); m_text.resize(size); - m_stream->serialize(m_text.mutableBuffer(), size); + m_stream->serialize(m_text.buffer(), size); m_text.pushBack('\0'); return m_text.buffer(); diff --git a/src/nvimage/FloatImage.cpp b/src/nvimage/FloatImage.cpp index 21fe43b..d789fd0 100644 --- a/src/nvimage/FloatImage.cpp +++ b/src/nvimage/FloatImage.cpp @@ -667,7 +667,7 @@ FloatImage * FloatImage::resize(const Filter & filter, uint w, uint h, WrapMode float * dst_channel = dst_image->channel(c); for (uint x = 0; x < w; x++) { - tmp_image->applyKernelVertical(ykernel, x, c, wm, tmp_column.mutableBuffer()); + tmp_image->applyKernelVertical(ykernel, x, c, wm, tmp_column.buffer()); for (uint y = 0; y < h; y++) { dst_channel[y * w + x] = tmp_column[y]; @@ -741,7 +741,7 @@ FloatImage * FloatImage::resize(const Filter & filter, uint w, uint h, WrapMode float * dst_channel = dst_image->channel(c); for (uint x = 0; x < w; x++) { - tmp_image->applyKernelVertical(ykernel, x, c, wm, tmp_column.mutableBuffer()); + tmp_image->applyKernelVertical(ykernel, x, c, wm, tmp_column.buffer()); for (uint y = 0; y < h; y++) { dst_channel[y * w + x] = tmp_column[y]; diff --git a/src/nvimage/ImageIO.cpp b/src/nvimage/ImageIO.cpp index 33cd432..318d79b 100644 --- a/src/nvimage/ImageIO.cpp +++ b/src/nvimage/ImageIO.cpp @@ -48,7 +48,7 @@ extern "C" { #if defined(HAVE_STBIMAGE) # define STBI_NO_STDIO -# include +# include #endif #endif // defined(HAVE_FREEIMAGE) @@ -99,9 +99,9 @@ namespace nv static bool saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); #endif - #if defined(HAVE_STBIMG) + #if defined(HAVE_STBIMAGE) static Image * loadSTB(Stream & s); - static Image * loadFloatSTB(Stream & s); + static FloatImage * loadFloatSTB(Stream & s); #endif #endif // defined(HAVE_FREEIMAGE) @@ -690,236 +690,236 @@ bool nv::ImageIO::saveFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s, const Fl /// Load TGA image. Image * nv::ImageIO::loadTGA(Stream & s) { - nvCheck(!s.isError()); - nvCheck(s.isLoading()); - - TgaHeader tga; - s << tga; - s.seek(TgaHeader::Size + tga.id_length); - - // Get header info. - bool rle = false; - bool pal = false; - bool rgb = false; - bool grey = false; - - switch( tga.image_type ) { - case TGA_TYPE_RLE_INDEXED: - rle = true; - // no break is intended! - case TGA_TYPE_INDEXED: - if( tga.colormap_type!=1 || tga.colormap_size!=24 || tga.colormap_length>256 ) { - nvDebug( "*** loadTGA: Error, only 24bit paletted images are supported.\n" ); - return false; - } - pal = true; - break; - - case TGA_TYPE_RLE_RGB: - rle = true; - // no break is intended! - case TGA_TYPE_RGB: - rgb = true; - break; - - case TGA_TYPE_RLE_GREY: - rle = true; - // no break is intended! - case TGA_TYPE_GREY: - grey = true; - break; - - default: - nvDebug( "*** loadTGA: Error, unsupported image type.\n" ); - return false; - } + nvCheck(!s.isError()); + nvCheck(s.isLoading()); - const uint pixel_size = (tga.pixel_size/8); - nvDebugCheck(pixel_size <= 4); - - const uint size = tga.width * tga.height * pixel_size; + TgaHeader tga; + s << tga; + s.seek(TgaHeader::Size + tga.id_length); + + // Get header info. + bool rle = false; + bool pal = false; + bool rgb = false; + bool grey = false; + + switch( tga.image_type ) { + case TGA_TYPE_RLE_INDEXED: + rle = true; + // no break is intended! + case TGA_TYPE_INDEXED: + if( tga.colormap_type!=1 || tga.colormap_size!=24 || tga.colormap_length>256 ) { + nvDebug( "*** loadTGA: Error, only 24bit paletted images are supported.\n" ); + return false; + } + pal = true; + break; - - // Read palette - uint8 palette[768]; - if( pal ) { - nvDebugCheck(tga.colormap_length <= 256); - s.serialize(palette, 3 * tga.colormap_length); - } + case TGA_TYPE_RLE_RGB: + rle = true; + // no break is intended! + case TGA_TYPE_RGB: + rgb = true; + break; + + case TGA_TYPE_RLE_GREY: + rle = true; + // no break is intended! + case TGA_TYPE_GREY: + grey = true; + break; + + default: + nvDebug( "*** loadTGA: Error, unsupported image type.\n" ); + return false; + } - // Decode image. - uint8 * mem = new uint8[size]; - if( rle ) { - // Decompress image in src. - uint8 * dst = mem; - int num = size; - - while (num > 0) { - // Get packet header - uint8 c; - s << c; - - uint count = (c & 0x7f) + 1; - num -= count * pixel_size; - - if (c & 0x80) { - // RLE pixels. - uint8 pixel[4]; // uint8 pixel[pixel_size]; - s.serialize( pixel, pixel_size ); - do { - memcpy(dst, pixel, pixel_size); - dst += pixel_size; - } while (--count); - } - else { - // Raw pixels. - count *= pixel_size; - //file->Read8(dst, count); - s.serialize(dst, count); - dst += count; - } - } - } - else { - s.serialize(mem, size); - } + const uint pixel_size = (tga.pixel_size/8); + nvDebugCheck(pixel_size <= 4); - // Allocate image. - AutoPtr img(new Image()); - img->allocate(tga.width, tga.height); + const uint size = tga.width * tga.height * pixel_size; - int lstep; - Color32 * dst; - if( tga.flags & TGA_ORIGIN_UPPER ) { - lstep = tga.width; - dst = img->pixels(); - } - else { - lstep = - tga.width; - dst = img->pixels() + (tga.height-1) * tga.width; - } - // Write image. - uint8 * src = mem; - if( pal ) { - for( int y = 0; y < tga.height; y++ ) { - for( int x = 0; x < tga.width; x++ ) { - uint8 idx = *src++; - dst[x].setBGRA(palette[3*idx+0], palette[3*idx+1], palette[3*idx+2], 0xFF); - } - dst += lstep; - } - } - else if( grey ) { - img->setFormat(Image::Format_ARGB); - - for( int y = 0; y < tga.height; y++ ) { - for( int x = 0; x < tga.width; x++ ) { - dst[x].setBGRA(*src, *src, *src, *src); - src++; - } - dst += lstep; - } - } - else { - - if( tga.pixel_size == 16 ) { - for( int y = 0; y < tga.height; y++ ) { - for( int x = 0; x < tga.width; x++ ) { - Color555 c = *reinterpret_cast(src); - uint8 b = (c.b << 3) | (c.b >> 2); - uint8 g = (c.g << 3) | (c.g >> 2); - uint8 r = (c.r << 3) | (c.r >> 2); - dst[x].setBGRA(b, g, r, 0xFF); - src += 2; - } - dst += lstep; - } - } - else if( tga.pixel_size == 24 ) { - for( int y = 0; y < tga.height; y++ ) { - for( int x = 0; x < tga.width; x++ ) { - dst[x].setBGRA(src[0], src[1], src[2], 0xFF); - src += 3; - } - dst += lstep; - } - } - else if( tga.pixel_size == 32 ) { - img->setFormat(Image::Format_ARGB); - - for( int y = 0; y < tga.height; y++ ) { - for( int x = 0; x < tga.width; x++ ) { - dst[x].setBGRA(src[0], src[1], src[2], src[3]); - src += 4; - } - dst += lstep; - } - } + // Read palette + uint8 palette[768]; + if( pal ) { + nvDebugCheck(tga.colormap_length <= 256); + s.serialize(palette, 3 * tga.colormap_length); + } + + // Decode image. + uint8 * mem = new uint8[size]; + if( rle ) { + // Decompress image in src. + uint8 * dst = mem; + int num = size; + + while (num > 0) { + // Get packet header + uint8 c; + s << c; + + uint count = (c & 0x7f) + 1; + num -= count * pixel_size; + + if (c & 0x80) { + // RLE pixels. + uint8 pixel[4]; // uint8 pixel[pixel_size]; + s.serialize( pixel, pixel_size ); + do { + memcpy(dst, pixel, pixel_size); + dst += pixel_size; + } while (--count); + } + else { + // Raw pixels. + count *= pixel_size; + //file->Read8(dst, count); + s.serialize(dst, count); + dst += count; + } } + } + else { + s.serialize(mem, size); + } + + // Allocate image. + AutoPtr img(new Image()); + img->allocate(tga.width, tga.height); + + int lstep; + Color32 * dst; + if( tga.flags & TGA_ORIGIN_UPPER ) { + lstep = tga.width; + dst = img->pixels(); + } + else { + lstep = - tga.width; + dst = img->pixels() + (tga.height-1) * tga.width; + } + + // Write image. + uint8 * src = mem; + if( pal ) { + for( int y = 0; y < tga.height; y++ ) { + for( int x = 0; x < tga.width; x++ ) { + uint8 idx = *src++; + dst[x].setBGRA(palette[3*idx+0], palette[3*idx+1], palette[3*idx+2], 0xFF); + } + dst += lstep; + } + } + else if( grey ) { + img->setFormat(Image::Format_ARGB); + + for( int y = 0; y < tga.height; y++ ) { + for( int x = 0; x < tga.width; x++ ) { + dst[x].setBGRA(*src, *src, *src, *src); + src++; + } + dst += lstep; + } + } + else { + + if( tga.pixel_size == 16 ) { + for( int y = 0; y < tga.height; y++ ) { + for( int x = 0; x < tga.width; x++ ) { + Color555 c = *reinterpret_cast(src); + uint8 b = (c.b << 3) | (c.b >> 2); + uint8 g = (c.g << 3) | (c.g >> 2); + uint8 r = (c.r << 3) | (c.r >> 2); + dst[x].setBGRA(b, g, r, 0xFF); + src += 2; + } + dst += lstep; + } + } + else if( tga.pixel_size == 24 ) { + for( int y = 0; y < tga.height; y++ ) { + for( int x = 0; x < tga.width; x++ ) { + dst[x].setBGRA(src[0], src[1], src[2], 0xFF); + src += 3; + } + dst += lstep; + } + } + else if( tga.pixel_size == 32 ) { + img->setFormat(Image::Format_ARGB); + + for( int y = 0; y < tga.height; y++ ) { + for( int x = 0; x < tga.width; x++ ) { + dst[x].setBGRA(src[0], src[1], src[2], src[3]); + src += 4; + } + dst += lstep; + } + } + } - // free uncompressed data. - delete [] mem; + // free uncompressed data. + delete [] mem; - return img.release(); + return img.release(); } /// Save TGA image. bool nv::ImageIO::saveTGA(Stream & s, const Image * img) { - nvCheck(!s.isError()); - nvCheck(img != NULL); - nvCheck(img->pixels() != NULL); - - TgaFile tga; - tga.head.id_length = 0; - tga.head.colormap_type = 0; - tga.head.image_type = TGA_TYPE_RGB; - - tga.head.colormap_index = 0; - tga.head.colormap_length = 0; - tga.head.colormap_size = 0; - - tga.head.x_origin = 0; - tga.head.y_origin = 0; - tga.head.width = img->width(); - tga.head.height = img->height(); - if(img->format() == Image::Format_ARGB) { - tga.head.pixel_size = 32; - tga.head.flags = TGA_ORIGIN_UPPER | TGA_HAS_ALPHA; - } - else { - tga.head.pixel_size = 24; - tga.head.flags = TGA_ORIGIN_UPPER; - } + nvCheck(!s.isError()); + nvCheck(img != NULL); + nvCheck(img->pixels() != NULL); + + TgaFile tga; + tga.head.id_length = 0; + tga.head.colormap_type = 0; + tga.head.image_type = TGA_TYPE_RGB; + + tga.head.colormap_index = 0; + tga.head.colormap_length = 0; + tga.head.colormap_size = 0; + + tga.head.x_origin = 0; + tga.head.y_origin = 0; + tga.head.width = img->width(); + tga.head.height = img->height(); + if(img->format() == Image::Format_ARGB) { + tga.head.pixel_size = 32; + tga.head.flags = TGA_ORIGIN_UPPER | TGA_HAS_ALPHA; + } + else { + tga.head.pixel_size = 24; + tga.head.flags = TGA_ORIGIN_UPPER; + } - // @@ Serialize directly. - tga.allocate(); - - const uint n = img->width() * img->height(); - if(img->format() == Image::Format_ARGB) { - for(uint i = 0; i < n; i++) { - Color32 color = img->pixel(i); - tga.mem[4 * i + 0] = color.b; - tga.mem[4 * i + 1] = color.g; - tga.mem[4 * i + 2] = color.r; - tga.mem[4 * i + 3] = color.a; - } - } - else { - for(uint i = 0; i < n; i++) { - Color32 color = img->pixel(i); - tga.mem[3 * i + 0] = color.b; - tga.mem[3 * i + 1] = color.g; - tga.mem[3 * i + 2] = color.r; - } - } + // @@ Serialize directly. + tga.allocate(); + + const uint n = img->width() * img->height(); + if(img->format() == Image::Format_ARGB) { + for(uint i = 0; i < n; i++) { + Color32 color = img->pixel(i); + tga.mem[4 * i + 0] = color.b; + tga.mem[4 * i + 1] = color.g; + tga.mem[4 * i + 2] = color.r; + tga.mem[4 * i + 3] = color.a; + } + } + else { + for(uint i = 0; i < n; i++) { + Color32 color = img->pixel(i); + tga.mem[3 * i + 0] = color.b; + tga.mem[3 * i + 1] = color.g; + tga.mem[3 * i + 2] = color.r; + } + } - s << tga; - - tga.free(); - - return true; + s << tga; + + tga.free(); + + return true; } /// Load PSD image. @@ -1078,248 +1078,247 @@ Image * nv::ImageIO::loadPSD(Stream & s) static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { - nvDebugCheck(png_ptr != NULL); + nvDebugCheck(png_ptr != NULL); - Stream * s = (Stream *)png_ptr->io_ptr; - s->serialize(data, (int)length); + Stream * s = (Stream *)png_get_io_ptr(png_ptr); + s->serialize(data, (int)length); - if (s->isError()) { - png_error(png_ptr, "Read Error"); - } + if (s->isError()) { + png_error(png_ptr, "Read Error"); + } } Image * nv::ImageIO::loadPNG(Stream & s) { - nvCheck(!s.isError()); - - // Set up a read buffer and check the library version - png_structp png_ptr; - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { - // nvDebug( "*** LoadPNG: Error allocating read buffer in file '%s'.\n", name ); - return false; - } + nvCheck(!s.isError()); - // Allocate/initialize a memory block for the image information - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - png_destroy_read_struct(&png_ptr, NULL, NULL); - // nvDebug( "*** LoadPNG: Error allocating image information for '%s'.\n", name ); - return false; - } + // Set up a read buffer and check the library version + png_structp png_ptr; + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) { + // nvDebug( "*** LoadPNG: Error allocating read buffer in file '%s'.\n", name ); + return false; + } - // Set up the error handling - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - // nvDebug( "*** LoadPNG: Error reading png file '%s'.\n", name ); - return false; - } + // Allocate/initialize a memory block for the image information + png_infop info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + // nvDebug( "*** LoadPNG: Error allocating image information for '%s'.\n", name ); + return false; + } - // Set up the I/O functions. - png_set_read_fn(png_ptr, (void*)&s, user_read_data); + // Set up the error handling + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + // nvDebug( "*** LoadPNG: Error reading png file '%s'.\n", name ); + return false; + } + // Set up the I/O functions. + png_set_read_fn(png_ptr, (void*)&s, user_read_data); - // Retrieve the image header information - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); + // Retrieve the image header information + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); - if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) { - // Convert indexed images to RGB. - png_set_expand(png_ptr); - } - else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { - // Convert grayscale to RGB. - png_set_expand(png_ptr); - } - else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - // Expand images with transparency to full alpha channels - // so the data will be available as RGBA quartets. - png_set_expand(png_ptr); - } - else if (bit_depth < 8) { - // If we have < 8 scale it up to 8. - //png_set_expand(png_ptr); - png_set_packing(png_ptr); - } - // Reduce bit depth. - if (bit_depth == 16) { - png_set_strip_16(png_ptr); - } + if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) { + // Convert indexed images to RGB. + png_set_expand(png_ptr); + } + else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { + // Convert grayscale to RGB. + png_set_expand(png_ptr); + } + else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + // Expand images with transparency to full alpha channels + // so the data will be available as RGBA quartets. + png_set_expand(png_ptr); + } + else if (bit_depth < 8) { + // If we have < 8 scale it up to 8. + //png_set_expand(png_ptr); + png_set_packing(png_ptr); + } - // Represent gray as RGB - if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - png_set_gray_to_rgb(png_ptr); - } + // Reduce bit depth. + if (bit_depth == 16) { + png_set_strip_16(png_ptr); + } - // Convert to RGBA filling alpha with 0xFF. - if (!(color_type & PNG_COLOR_MASK_ALPHA)) { - png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); - } + // Represent gray as RGB + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + png_set_gray_to_rgb(png_ptr); + } - // @todo Choose gamma according to the platform? - double screen_gamma = 2.2; - int intent; - if (png_get_sRGB(png_ptr, info_ptr, &intent)) { - png_set_gamma(png_ptr, screen_gamma, 0.45455); - } - else { - double image_gamma; - if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) { - png_set_gamma(png_ptr, screen_gamma, image_gamma); - } - else { - png_set_gamma(png_ptr, screen_gamma, 0.45455); - } - } + // Convert to RGBA filling alpha with 0xFF. + if (!(color_type & PNG_COLOR_MASK_ALPHA)) { + png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); + } - // Perform the selected transforms. - png_read_update_info(png_ptr, info_ptr); + // @todo Choose gamma according to the platform? + double screen_gamma = 2.2; + int intent; + if (png_get_sRGB(png_ptr, info_ptr, &intent)) { + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + else { + double image_gamma; + if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) { + png_set_gamma(png_ptr, screen_gamma, image_gamma); + } + else { + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + } - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); + // Perform the selected transforms. + png_read_update_info(png_ptr, info_ptr); - AutoPtr img(new Image()); - img->allocate(width, height); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); - // Set internal format flags. - if(color_type & PNG_COLOR_MASK_COLOR) { - //img->flags |= PI_IF_HAS_COLOR; - } - if(color_type & PNG_COLOR_MASK_ALPHA) { - //img->flags |= PI_IF_HAS_ALPHA; - img->setFormat(Image::Format_ARGB); - } + AutoPtr img(new Image()); + img->allocate(width, height); - // Read the image - uint8 * pixels = (uint8 *)img->pixels(); - png_bytep * row_data = new png_bytep[sizeof(png_byte) * height]; - for (uint i = 0; i < height; i++) { - row_data[i] = &(pixels[width * 4 * i]); - } + // Set internal format flags. + if(color_type & PNG_COLOR_MASK_COLOR) { + //img->flags |= PI_IF_HAS_COLOR; + } + if(color_type & PNG_COLOR_MASK_ALPHA) { + //img->flags |= PI_IF_HAS_ALPHA; + img->setFormat(Image::Format_ARGB); + } - png_read_image(png_ptr, row_data); - delete [] row_data; + // Read the image + uint8 * pixels = (uint8 *)img->pixels(); + png_bytep * row_data = new png_bytep[sizeof(png_byte) * height]; + for (uint i = 0; i < height; i++) { + row_data[i] = &(pixels[width * 4 * i]); + } - // Finish things up - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_read_image(png_ptr, row_data); + delete [] row_data; - // RGBA to BGRA. - uint num = width * height; - for(uint i = 0; i < num; i++) - { - Color32 c = img->pixel(i); - img->pixel(i) = Color32(c.b, c.g, c.r, c.a); - } + // Finish things up + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - // Compute alpha channel if needed. - /*if( img->flags & PI_IU_BUMPMAP || img->flags & PI_IU_ALPHAMAP ) { - if( img->flags & PI_IF_HAS_COLOR && !(img->flags & PI_IF_HAS_ALPHA)) { - img->ComputeAlphaFromColor(); - } - }*/ + // RGBA to BGRA. + uint num = width * height; + for(uint i = 0; i < num; i++) + { + Color32 c = img->pixel(i); + img->pixel(i) = Color32(c.b, c.g, c.r, c.a); + } - return img.release(); + // Compute alpha channel if needed. + /*if( img->flags & PI_IU_BUMPMAP || img->flags & PI_IU_ALPHAMAP ) { + if( img->flags & PI_IF_HAS_COLOR && !(img->flags & PI_IF_HAS_ALPHA)) { + img->ComputeAlphaFromColor(); + } + }*/ + + return img.release(); } static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { - nvDebugCheck(png_ptr != NULL); + nvDebugCheck(png_ptr != NULL); - Stream * s = (Stream *)png_ptr->io_ptr; - s->serialize(data, (int)length); + Stream * s = (Stream *)png_get_io_ptr(png_ptr); + s->serialize(data, (int)length); - if (s->isError()) { - png_error(png_ptr, "Write Error"); - } + if (s->isError()) { + png_error(png_ptr, "Write Error"); + } } static void user_write_flush(png_structp png_ptr) { } bool nv::ImageIO::savePNG(Stream & s, const Image * img, const ImageMetaData * tags/*=NULL*/) { - nvCheck(!s.isError()); - nvCheck(img != NULL); - nvCheck(img->pixels() != NULL); - - // Set up a write buffer and check the library version - png_structp png_ptr; - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { - return false; - } + nvCheck(!s.isError()); + nvCheck(img != NULL); + nvCheck(img->pixels() != NULL); + + // Set up a write buffer and check the library version + png_structp png_ptr; + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) { + return false; + } - // Allocate/initialize a memory block for the image information - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - png_destroy_write_struct(&png_ptr, NULL); - return false; - } + // Allocate/initialize a memory block for the image information + png_infop info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + png_destroy_write_struct(&png_ptr, NULL); + return false; + } - // Set up the error handling - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_write_struct(&png_ptr, &info_ptr); - return false; - } + // Set up the error handling + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + return false; + } - // Set up the I/O functions. - png_set_write_fn(png_ptr, (void*)&s, user_write_data, user_write_flush); + // Set up the I/O functions. + png_set_write_fn(png_ptr, (void*)&s, user_write_data, user_write_flush); - // Set image header information - int color_type = PNG_COLOR_TYPE_RGBA; - switch(img->format()) - { - case Image::Format_RGB: color_type = PNG_COLOR_TYPE_RGB; break; - case Image::Format_ARGB: color_type = PNG_COLOR_TYPE_RGBA; break; - } - png_set_IHDR(png_ptr, info_ptr, img->width(), img->height(), - 8, color_type, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - // Set image data - png_bytep * row_data = new png_bytep[sizeof(png_byte) * img->height()]; - for (uint i = 0; i < img->height(); i++) { - row_data[i] = (png_byte*)img->scanline (i); + // Set image header information + int color_type = PNG_COLOR_TYPE_RGBA; + switch(img->format()) + { + case Image::Format_RGB: color_type = PNG_COLOR_TYPE_RGB; break; + case Image::Format_ARGB: color_type = PNG_COLOR_TYPE_RGBA; break; + } + png_set_IHDR(png_ptr, info_ptr, img->width(), img->height(), + 8, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + // Set image data + png_bytep * row_data = new png_bytep[sizeof(png_byte) * img->height()]; + for (uint i = 0; i < img->height(); i++) { + row_data[i] = (png_byte*)img->scanline (i); if (img->format() == Image::Format_RGB) row_data[i]--; // This is a bit of a hack, libpng expects images in ARGB format not BGRA, it supports BGR swapping, but not alpha swapping. - } - png_set_rows(png_ptr, info_ptr, row_data); + } + png_set_rows(png_ptr, info_ptr, row_data); - png_text * text = NULL; + png_text * text = NULL; if (tags != NULL && tags->tagMap.count() > 0) - { - text = new png_text[tags->tagMap.count()]; - memset(text, 0, tags->tagMap.count() * sizeof(png_text)); - int n = 0; - foreach (i, tags->tagMap) - { - text[n].compression = PNG_TEXT_COMPRESSION_NONE; - text[n].key = const_cast (tags->tagMap[i].key.str()); - text[n].text = const_cast (tags->tagMap[i].value.str()); - n++; - } - png_set_text(png_ptr, info_ptr, text, tags->tagMap.count()); - } + { + text = new png_text[tags->tagMap.count()]; + memset(text, 0, tags->tagMap.count() * sizeof(png_text)); + int n = 0; + foreach (i, tags->tagMap) + { + text[n].compression = PNG_TEXT_COMPRESSION_NONE; + text[n].key = const_cast (tags->tagMap[i].key.str()); + text[n].text = const_cast (tags->tagMap[i].value.str()); + n++; + } + png_set_text(png_ptr, info_ptr, text, tags->tagMap.count()); + } - png_write_png(png_ptr, info_ptr, - // component order is BGR(A) + png_write_png(png_ptr, info_ptr, + // component order is BGR(A) PNG_TRANSFORM_BGR | - // Strip alpha byte for RGB images - (img->format() == Image::Format_RGB ? PNG_TRANSFORM_STRIP_FILLER : 0) - , - NULL); + // Strip alpha byte for RGB images + (img->format() == Image::Format_RGB ? PNG_TRANSFORM_STRIP_FILLER : 0) + , NULL); - // Finish things up - png_destroy_write_struct(&png_ptr, &info_ptr); + // Finish things up + png_destroy_write_struct(&png_ptr, &info_ptr); - delete [] row_data; - delete [] text; + delete [] row_data; + delete [] text; - return true; + return true; } #endif // defined(HAVE_PNG) @@ -1329,106 +1328,106 @@ bool nv::ImageIO::savePNG(Stream & s, const Image * img, const ImageMetaData * t static void init_source (j_decompress_ptr /*cinfo*/){ } -static boolean fill_input_buffer (j_decompress_ptr cinfo){ - struct jpeg_source_mgr * src = cinfo->src; - static JOCTET FakeEOI[] = { 0xFF, JPEG_EOI }; +static boolean fill_input_buffer (j_decompress_ptr cinfo) { + struct jpeg_source_mgr * src = cinfo->src; + static JOCTET FakeEOI[] = { 0xFF, JPEG_EOI }; - // Generate warning - nvDebug("jpeglib: Premature end of file\n"); + // Generate warning + nvDebug("jpeglib: Premature end of file\n"); - // Insert a fake EOI marker - src->next_input_byte = FakeEOI; - src->bytes_in_buffer = 2; + // Insert a fake EOI marker + src->next_input_byte = FakeEOI; + src->bytes_in_buffer = 2; - return TRUE; + return TRUE; } static void skip_input_data (j_decompress_ptr cinfo, long num_bytes) { - struct jpeg_source_mgr * src = cinfo->src; + struct jpeg_source_mgr * src = cinfo->src; - if(num_bytes >= (long)src->bytes_in_buffer) { - fill_input_buffer(cinfo); - return; - } + if(num_bytes >= (long)src->bytes_in_buffer) { + fill_input_buffer(cinfo); + return; + } - src->bytes_in_buffer -= num_bytes; - src->next_input_byte += num_bytes; + src->bytes_in_buffer -= num_bytes; + src->next_input_byte += num_bytes; } static void term_source (j_decompress_ptr /*cinfo*/){ - // no work necessary here + // no work necessary here } Image * nv::ImageIO::loadJPG(Stream & s) { - nvCheck(!s.isError()); - - // Read the entire file. - Array byte_array; - byte_array.resize(s.size()); - s.serialize(byte_array.mutableBuffer(), s.size()); - - jpeg_decompress_struct cinfo; - jpeg_error_mgr jerr; - - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - - cinfo.src = (struct jpeg_source_mgr *) (*cinfo.mem->alloc_small) - ((j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr)); - cinfo.src->init_source = init_source; - cinfo.src->fill_input_buffer = fill_input_buffer; - cinfo.src->skip_input_data = skip_input_data; - cinfo.src->resync_to_restart = jpeg_resync_to_restart; // use default method - cinfo.src->term_source = term_source; - cinfo.src->bytes_in_buffer = byte_array.size(); - cinfo.src->next_input_byte = byte_array.buffer(); - - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - - /* - cinfo.do_fancy_upsampling = FALSE; // fast decompression - cinfo.dct_method = JDCT_FLOAT; // Choose floating point DCT method. - */ - - uint8 * tmp_buffer = new uint8 [cinfo.output_width * cinfo.output_height * cinfo.num_components]; - uint8 * scanline = tmp_buffer; - - while( cinfo.output_scanline < cinfo.output_height ){ - int num_scanlines = jpeg_read_scanlines (&cinfo, &scanline, 1); - scanline += num_scanlines * cinfo.output_width * cinfo.num_components; - } + nvCheck(!s.isError()); - jpeg_finish_decompress(&cinfo); + // Read the entire file. + Array byte_array; + byte_array.resize(s.size()); + s.serialize(byte_array.mutableBuffer(), s.size()); + + jpeg_decompress_struct cinfo; + jpeg_error_mgr jerr; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + cinfo.src = (struct jpeg_source_mgr *) (*cinfo.mem->alloc_small) + ((j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr)); + cinfo.src->init_source = init_source; + cinfo.src->fill_input_buffer = fill_input_buffer; + cinfo.src->skip_input_data = skip_input_data; + cinfo.src->resync_to_restart = jpeg_resync_to_restart; // use default method + cinfo.src->term_source = term_source; + cinfo.src->bytes_in_buffer = byte_array.size(); + cinfo.src->next_input_byte = byte_array.buffer(); + + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + /* + cinfo.do_fancy_upsampling = FALSE; // fast decompression + cinfo.dct_method = JDCT_FLOAT; // Choose floating point DCT method. + */ + + uint8 * tmp_buffer = new uint8 [cinfo.output_width * cinfo.output_height * cinfo.num_components]; + uint8 * scanline = tmp_buffer; + + while( cinfo.output_scanline < cinfo.output_height ){ + int num_scanlines = jpeg_read_scanlines (&cinfo, &scanline, 1); + scanline += num_scanlines * cinfo.output_width * cinfo.num_components; + } - AutoPtr img(new Image()); - img->allocate(cinfo.output_width, cinfo.output_height); + jpeg_finish_decompress(&cinfo); - Color32 * dst = img->pixels(); - const int size = img->height() * img->width(); - const uint8 * src = tmp_buffer; + AutoPtr img(new Image()); + img->allocate(cinfo.output_width, cinfo.output_height); - if( cinfo.num_components == 3 ) { - img->setFormat(Image::Format_RGB); - for( int i = 0; i < size; i++ ) { - *dst++ = Color32(src[0], src[1], src[2]); - src += 3; - } - } - else { - img->setFormat(Image::Format_ARGB); - for( int i = 0; i < size; i++ ) { - *dst++ = Color32(*src, *src, *src, *src); - src++; - } - } + Color32 * dst = img->pixels(); + const int size = img->height() * img->width(); + const uint8 * src = tmp_buffer; + + if( cinfo.num_components == 3 ) { + img->setFormat(Image::Format_RGB); + for( int i = 0; i < size; i++ ) { + *dst++ = Color32(src[0], src[1], src[2]); + src += 3; + } + } + else { + img->setFormat(Image::Format_ARGB); + for( int i = 0; i < size; i++ ) { + *dst++ = Color32(*src, *src, *src, *src); + src++; + } + } - delete [] tmp_buffer; - jpeg_destroy_decompress (&cinfo); + delete [] tmp_buffer; + jpeg_destroy_decompress (&cinfo); - return img.release(); + return img.release(); } #endif // defined(HAVE_JPEG) @@ -1438,195 +1437,193 @@ Image * nv::ImageIO::loadJPG(Stream & s) /* static tsize_t tiffReadWriteProc(thandle_t h, tdata_t ptr, tsize_t size) { - Stream * s = (Stream *)h; - nvDebugCheck(s != NULL); + Stream * s = (Stream *)h; + nvDebugCheck(s != NULL); - s->serialize(ptr, size); + s->serialize(ptr, size); - return size; + return size; } static toff_t tiffSeekProc(thandle_t h, toff_t offset, int whence) { - Stream * s = (Stream *)h; - nvDebugCheck(s != NULL); + Stream * s = (Stream *)h; + nvDebugCheck(s != NULL); - if (!s->isSeekable()) - { - return (toff_t)-1; - } + if (!s->isSeekable()) + { + return (toff_t)-1; + } - if (whence == SEEK_SET) - { - s->seek(offset); - } - else if (whence == SEEK_CUR) - { - s->seek(s->tell() + offset); - } - else if (whence == SEEK_END) - { - s->seek(s->size() + offset); - } + if (whence == SEEK_SET) + { + s->seek(offset); + } + else if (whence == SEEK_CUR) + { + s->seek(s->tell() + offset); + } + else if (whence == SEEK_END) + { + s->seek(s->size() + offset); + } - return s->tell(); + return s->tell(); } static int tiffCloseProc(thandle_t) { - return 0; + return 0; } static toff_t tiffSizeProc(thandle_t h) { - Stream * s = (Stream *)h; - nvDebugCheck(s != NULL); - return s->size(); + Stream * s = (Stream *)h; + nvDebugCheck(s != NULL); + return s->size(); } static int tiffMapFileProc(thandle_t, tdata_t*, toff_t*) { - // @@ TODO, Implement these functions. - return -1; + // @@ TODO, Implement these functions. + return -1; } static void tiffUnmapFileProc(thandle_t, tdata_t, toff_t) { - // @@ TODO, Implement these functions. + // @@ TODO, Implement these functions. } */ FloatImage * nv::ImageIO::loadFloatTIFF(const char * fileName, Stream & s) { - nvCheck(!s.isError()); + nvCheck(!s.isError()); - TIFF * tif = TIFFOpen(fileName, "r"); - //TIFF * tif = TIFFClientOpen(fileName, "r", &s, tiffReadWriteProc, tiffReadWriteProc, tiffSeekProc, tiffCloseProc, tiffSizeProc, tiffMapFileProc, tiffUnmapFileProc); + TIFF * tif = TIFFOpen(fileName, "r"); + //TIFF * tif = TIFFClientOpen(fileName, "r", &s, tiffReadWriteProc, tiffReadWriteProc, tiffSeekProc, tiffCloseProc, tiffSizeProc, tiffMapFileProc, tiffUnmapFileProc); - if (!tif) - { - nvDebug("Can't open '%s' for reading\n", fileName); - return NULL; - } + if (!tif) + { + nvDebug("Can't open '%s' for reading\n", fileName); + return NULL; + } - ::uint16 spp, bpp, format; - ::uint32 width, height; - TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); - TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp); - TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp); - TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &format); - - if (bpp != 8 && bpp != 16 && bpp != 32) { - nvDebug("Can't load '%s', only 1 sample per pixel supported\n", fileName); - TIFFClose(tif); - return NULL; - } + ::uint16 spp, bpp, format; + ::uint32 width, height; + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &format); + + if (bpp != 8 && bpp != 16 && bpp != 32) { + nvDebug("Can't load '%s', only 1 sample per pixel supported\n", fileName); + TIFFClose(tif); + return NULL; + } - AutoPtr fimage(new FloatImage()); - fimage->allocate(spp, width, height); + AutoPtr fimage(new FloatImage()); + fimage->allocate(spp, width, height); - int linesize = TIFFScanlineSize(tif); - tdata_t buf = malloc(linesize); + int linesize = TIFFScanlineSize(tif); + tdata_t buf = malloc(linesize); - for (uint y = 0; y < height; y++) + for (uint y = 0; y < height; y++) + { + TIFFReadScanline(tif, buf, y, 0); + + for (uint c=0; cscanline(y, c); - for (uint c=0; cscanline(y, c); - - for(uint x = 0; x < width; x++) - { - if (bpp == 8) - { - dst[x] = float(((::uint8 *)buf)[x*spp+c]) / float(0xFF); - } - else if (bpp == 16) - { - dst[x] = float(((::uint16 *)buf)[x*spp+c]) / float(0xFFFF); - } - else if (bpp == 32) - { - if (format==SAMPLEFORMAT_IEEEFP) - { - dst[x] = float(((float *)buf)[x*spp+c]); - } - else - { - dst[x] = float(((::uint32 *)buf)[x*spp+c] >> 8) / float(0xFFFFFF); - } - - } - - } + dst[x] = float(((::uint8 *)buf)[x*spp+c]) / float(0xFF); } + else if (bpp == 16) + { + dst[x] = float(((::uint16 *)buf)[x*spp+c]) / float(0xFFFF); + } + else if (bpp == 32) + { + if (format==SAMPLEFORMAT_IEEEFP) + { + dst[x] = float(((float *)buf)[x*spp+c]); + } + else + { + dst[x] = float(((::uint32 *)buf)[x*spp+c] >> 8) / float(0xFFFFFF); + } + } + } } + } - free(buf); + free(buf); - TIFFClose(tif); + TIFFClose(tif); - return fimage.release(); + return fimage.release(); } bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components) { - nvCheck(fileName != NULL); - nvCheck(fimage != NULL); - nvCheck(base_component + num_components <= fimage->componentNum()); + nvCheck(fileName != NULL); + nvCheck(fimage != NULL); + nvCheck(base_component + num_components <= fimage->componentNum()); - const int iW = fimage->width(); - const int iH = fimage->height(); - const int iC = num_components; + const int iW = fimage->width(); + const int iH = fimage->height(); + const int iC = num_components; - TIFF * image = TIFFOpen(fileName, "w"); + TIFF * image = TIFFOpen(fileName, "w"); - // Open the TIFF file - if (image == NULL) - { - nvDebug("Could not open '%s' for writing\n", fileName); - return false; - } + // Open the TIFF file + if (image == NULL) + { + nvDebug("Could not open '%s' for writing\n", fileName); + return false; + } - TIFFSetField(image, TIFFTAG_IMAGEWIDTH, iW); - TIFFSetField(image, TIFFTAG_IMAGELENGTH, iH); - TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, iC); - TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); - TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(image, TIFFTAG_IMAGEWIDTH, iW); + TIFFSetField(image, TIFFTAG_IMAGELENGTH, iH); + TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, iC); + TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 32); - uint32 rowsperstrip = TIFFDefaultStripSize(image, (uint32)-1); + uint32 rowsperstrip = TIFFDefaultStripSize(image, (uint32)-1); - TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); - TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); - if (num_components == 3) - { - // Set this so that it can be visualized with pfstools. - TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); - } - TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); + if (num_components == 3) + { + // Set this so that it can be visualized with pfstools. + TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + } + TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - float * scanline = new float[iW * iC]; - for (int y = 0; y < iH; y++) - { - for (int c = 0; c < iC; c++) - { - const float * src = fimage->scanline(y, base_component + c); - for (int x = 0; x < iW; x++) scanline[x * iC + c] = src[x]; - } - if (TIFFWriteScanline(image, scanline, y, 0)==-1) - { - nvDebug("Error writing scanline %d\n", y); - return false; - } - } - delete [] scanline; + float * scanline = new float[iW * iC]; + for (int y = 0; y < iH; y++) + { + for (int c = 0; c < iC; c++) + { + const float * src = fimage->scanline(y, base_component + c); + for (int x = 0; x < iW; x++) scanline[x * iC + c] = src[x]; + } + if (TIFFWriteScanline(image, scanline, y, 0)==-1) + { + nvDebug("Error writing scanline %d\n", y); + return false; + } + } + delete [] scanline; - // Close the file - TIFFClose(image); - return true; + // Close the file + TIFFClose(image); + return true; } #endif @@ -1635,159 +1632,158 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage namespace { - class ExrStream : public Imf::IStream - { - public: - ExrStream(const char * name, Stream & s) : Imf::IStream(name), m_stream(s) - { - nvDebugCheck(s.isLoading()); - } - - virtual bool read(char c[], int n) - { - m_stream.serialize(c, n); - - if (m_stream.isError()) - { - throw Iex::InputExc("I/O error."); - } + class ExrStream : public Imf::IStream + { + public: + ExrStream(const char * name, Stream & s) : Imf::IStream(name), m_stream(s) + { + nvDebugCheck(s.isLoading()); + } - return m_stream.isAtEnd(); - } + virtual bool read(char c[], int n) + { + m_stream.serialize(c, n); - virtual Imf::Int64 tellg() - { - return m_stream.tell(); - } + if (m_stream.isError()) + { + throw Iex::InputExc("I/O error."); + } - virtual void seekg(Imf::Int64 pos) - { - nvDebugCheck(pos >= 0 && pos < UINT_MAX); - m_stream.seek((uint)pos); - } + return m_stream.isAtEnd(); + } - virtual void clear() - { - m_stream.clearError(); - } + virtual Imf::Int64 tellg() + { + return m_stream.tell(); + } - private: - Stream & m_stream; - }; + virtual void seekg(Imf::Int64 pos) + { + nvDebugCheck(pos >= 0 && pos < UINT_MAX); + m_stream.seek((uint)pos); + } - static int channelIndexFromName(const char* name) + virtual void clear() { - char c = tolower(name[0]); - switch (c) - { - default: - case 'r': - return 0; - case 'g': - return 1; - case 'b': - return 2; - case 'a': - return 3; - } + m_stream.clearError(); } + private: + Stream & m_stream; + }; + + static int channelIndexFromName(const char* name) + { + char c = tolower(name[0]); + switch (c) + { + default: + case 'r': + return 0; + case 'g': + return 1; + case 'b': + return 2; + case 'a': + return 3; + } + } + } // namespace FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) { - nvCheck(s.isLoading()); - nvCheck(!s.isError()); + nvCheck(s.isLoading()); + nvCheck(!s.isError()); - ExrStream stream(fileName, s); - Imf::InputFile inputFile(stream); + ExrStream stream(fileName, s); + Imf::InputFile inputFile(stream); - Imath::Box2i box = inputFile.header().dataWindow(); + Imath::Box2i box = inputFile.header().dataWindow(); - int width = box.max.x - box.min.y + 1; - int height = box.max.x - box.min.y + 1; + int width = box.max.x - box.min.y + 1; + int height = box.max.x - box.min.y + 1; - const Imf::ChannelList & channels = inputFile.header().channels(); + const Imf::ChannelList & channels = inputFile.header().channels(); - // Count channels. - uint channelCount= 0; - for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it) - { - channelCount++; - } + // Count channels. + uint channelCount= 0; + for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it) + { + channelCount++; + } - // Allocate FloatImage. - AutoPtr fimage(new FloatImage()); - fimage->allocate(channelCount, width, height); + // Allocate FloatImage. + AutoPtr fimage(new FloatImage()); + fimage->allocate(channelCount, width, height); - // Describe image's layout with a framebuffer. - Imf::FrameBuffer frameBuffer; - uint i = 0; - for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it, ++i) - { - int channelIndex = channelIndexFromName(it.name()); - frameBuffer.insert(it.name(), Imf::Slice(Imf::FLOAT, (char *)fimage->channel(channelIndex), sizeof(float), sizeof(float) * width)); - } + // Describe image's layout with a framebuffer. + Imf::FrameBuffer frameBuffer; + uint i = 0; + for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it, ++i) + { + int channelIndex = channelIndexFromName(it.name()); + frameBuffer.insert(it.name(), Imf::Slice(Imf::FLOAT, (char *)fimage->channel(channelIndex), sizeof(float), sizeof(float) * width)); + } - // Read it. - inputFile.setFrameBuffer (frameBuffer); - inputFile.readPixels (box.min.y, box.max.y); + // Read it. + inputFile.setFrameBuffer (frameBuffer); + inputFile.readPixels (box.min.y, box.max.y); - return fimage.release(); + return fimage.release(); } bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components) { - nvCheck(fileName != NULL); - nvCheck(fimage != NULL); - nvCheck(base_component + num_components <= fimage->componentNum()); - nvCheck(num_components > 0 && num_components <= 4); + nvCheck(fileName != NULL); + nvCheck(fimage != NULL); + nvCheck(base_component + num_components <= fimage->componentNum()); + nvCheck(num_components > 0 && num_components <= 4); - const int w = fimage->width(); - const int h = fimage->height(); + const int w = fimage->width(); + const int h = fimage->height(); - const char * channelNames[] = {"R", "G", "B", "A"}; + const char * channelNames[] = {"R", "G", "B", "A"}; - Imf::Header header (w, h); + Imf::Header header (w, h); - for (uint c = 0; c < num_components; c++) - { - header.channels().insert(channelNames[c], Imf::Channel(Imf::FLOAT)); - } + for (uint c = 0; c < num_components; c++) + { + header.channels().insert(channelNames[c], Imf::Channel(Imf::FLOAT)); + } - Imf::OutputFile file(fileName, header); - Imf::FrameBuffer frameBuffer; + Imf::OutputFile file(fileName, header); + Imf::FrameBuffer frameBuffer; - for (uint c = 0; c < num_components; c++) - { - char * channel = (char *) fimage->channel(base_component + c); - frameBuffer.insert(channelNames[c], Imf::Slice(Imf::FLOAT, channel, sizeof(float), sizeof(float) * w)); - } + for (uint c = 0; c < num_components; c++) + { + char * channel = (char *) fimage->channel(base_component + c); + frameBuffer.insert(channelNames[c], Imf::Slice(Imf::FLOAT, channel, sizeof(float), sizeof(float) * w)); + } - file.setFrameBuffer(frameBuffer); - file.writePixels(h); + file.setFrameBuffer(frameBuffer); + file.writePixels(h); - return true; + return true; } #endif // defined(HAVE_OPENEXR) -#if defined(HAVE_STBIMG) +#if defined(HAVE_STBIMAGE) Image * nv::ImageIO::loadSTB(Stream & s) { // @@ Assumes stream cursor is at the beginning and that image occupies the whole stream. - const int len = s.size(); + const int size = s.size(); uint8 * buffer = new uint8[size]; - s.serialize(buffer, len); + s.serialize(buffer, size); int w, h, n; - uint8 * data = stbi_load_from_memory(buffer, len, &w, &h, &n, 4); + uint8 * data = stbi_load_from_memory(buffer, size, &w, &h, &n, 4); delete buffer; - // Copy to image. if (data != NULL) { Image * img = new Image; img->wrap(data, w, h); @@ -1801,27 +1797,37 @@ Image * nv::ImageIO::loadSTB(Stream & s) FloatImage * loadFloatSTB(Stream & s) { // @@ Assumes stream cursor is at the beginning and that image occupies the whole stream. - const int len = s.size(); + const int size = s.size(); uint8 * buffer = new uint8[size]; - s.serialize(buffer, len); + s.serialize(buffer, size); int w, h, n; - float * data = stbi_loadf_from_memory(buffer, len, &w, &h, &n, 0); + float * data = stbi_loadf_from_memory(buffer, size, &w, &h, &n, 0); delete buffer; // Copy to image. if (data != NULL) { FloatImage * img = new FloatImage; - img->wrap(n, w, h); + img->allocate(n, w, h); + + const int count = w * h; + + for (int c = 0; c < n; c++) { + float * dst = img->channel(c); + + for (int i = 0; i < count; i++) { + dst[i] = data[i*n + c]; + } + } return img; } return NULL; } -#endif // defined(HAVE_STBIMG) +#endif // defined(HAVE_STBIMAGE) #endif // defined(HAVE_FREEIMAGE)